using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Text;
using Rage.Base;
using Rage.Base.Abilities;
using Rage.Base.Abilities.sith_warrior;

namespace Rage.Juggernaut
{
    public sealed class CollectedCharacterJuggernaut : CollectedCharacter
    {
        public CollectedCharacterJuggernaut() { }
        public DefendModel DefendModel { get; set; }
        private CalculationOptionsJuggernaut _calcOpts;
        public new CalculationOptionsJuggernaut CalcOpts
        {
            get { return _calcOpts; }
            set { _calcOpts = value; }
        }
        /*private CombatFactorsJuggernaut _CombatFactors;
        public new CombatFactorsJuggernaut CombatFactors
        {
            get { return _CombatFactors; }
            set { _CombatFactors = value; }
        }*/
        /*private StatsWarrior _statsWarrior;
        public new StatsWarrior StatS
        {
            get { return _statsWarrior; }
            set { _statsWarrior = value; }
        }*/
        private JuggernautTalents _talentsJuggernaut;
        public new JuggernautTalents Talents
        {
            get { return _talentsJuggernaut; }
            set { _talentsJuggernaut = value; }
        }
    }
    [Rage.Calculations.RageModelInfo("Juggernaut", "Ability_Warrior_DefensiveStance", CharacterClass.Juggernaut)]
    public class CalculationsJuggernaut : CalculationsBase
    {
        #region Variables and Properties

        public override List<GemmingTemplate> DefaultGemmingTemplates
        {
            get
            {
                // Relevant Mod IDs for Class

                Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<int, string>>>> templates = new Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<int, string>>>>();
                //
                templates["Armoring"] = new Dictionary<string, Dictionary<string, Dictionary<int, string>>>();
                templates["Barrel"] = new Dictionary<string, Dictionary<string, Dictionary<int, string>>>();
                templates["Hilt"] = new Dictionary<string, Dictionary<string, Dictionary<int, string>>>();
                templates["Modification"] = new Dictionary<string, Dictionary<string, Dictionary<int, string>>>();
                templates["Enhancement"] = new Dictionary<string, Dictionary<string, Dictionary<int, string>>>();
                templates["ColorCrystal"] = new Dictionary<string, Dictionary<string, Dictionary<int, string>>>();
                templates["Augment"] = new Dictionary<string, Dictionary<string, Dictionary<int, string>>>();
                //
                templates["Armoring"]["Defensive"] = new Dictionary<string, Dictionary<int, string>>();
                templates["Barrel"]["Defensive"] = new Dictionary<string, Dictionary<int, string>>();
                templates["Hilt"]["Defensive"] = new Dictionary<string, Dictionary<int, string>>();
                templates["Modification"]["Defensive"] = new Dictionary<string, Dictionary<int, string>>();
                templates["Enhancement"]["Defensive"] = new Dictionary<string, Dictionary<int, string>>();
                templates["ColorCrystal"]["Defensive"] = new Dictionary<string, Dictionary<int, string>>();
                templates["Augment"]["Defensive"] = new Dictionary<string, Dictionary<int, string>>();
                //templates["Armoring"]["Offensive"] = new Dictionary<string, Dictionary<int, string>>();
                //templates["Barrel"]["Offensive"] = new Dictionary<string, Dictionary<int, string>>();
                //templates["Hilt"]["Offensive"] = new Dictionary<string, Dictionary<int, string>>();
                //templates["Modification"]["Offensive"] = new Dictionary<string, Dictionary<int, string>>();
                //templates["Enhancement"]["Offensive"] = new Dictionary<string, Dictionary<int, string>>();
                //templates["ColorCrystal"]["Offensive"] = new Dictionary<string, Dictionary<int, string>>();
                //templates["Augment"]["Offensive"] = new Dictionary<string, Dictionary<int, string>>();
                // Armoring/Hilt | Guardian, Guardian Master
                templates["Armoring"]["Defensive"]["22/50-Green"]        = new Dictionary<int, string>() { { 1, "483690" }, { 2, "483690" } };
                templates["Armoring"]["Defensive"]["22/50-Blue"]         = new Dictionary<int, string>() { { 1, "483518" }, { 2, "483518" } };
                templates["Armoring"]["Defensive"]["22/50-Purple"]       = new Dictionary<int, string>() { { 1, "483691" }, { 2, "622240" } };
                templates["Armoring"]["Defensive"]["23/51-Tionese"]      = new Dictionary<int, string>() { { 1, "613297" }, { 2, "628234" } };
                templates["Armoring"]["Defensive"]["24/56-Columi"]       = new Dictionary<int, string>() { { 1, "641296" }, { 2, "641298" } };
                templates["Armoring"]["Defensive"]["25/58-Rakata"]       = new Dictionary<int, string>() { { 1, "641297" }, { 2, "641299" } };
                templates["Hilt"]["Defensive"]["22/50-Green"]            = new Dictionary<int, string>() { { 1, "483640" }, { 2, "483640" } };
                templates["Hilt"]["Defensive"]["22/50-Blue"]             = new Dictionary<int, string>() { { 1, "483509" }, { 2, "483509" } };
                templates["Hilt"]["Defensive"]["22/50-Purple"]           = new Dictionary<int, string>() { { 1, "508166" }, { 2, "628500" } };
                templates["Hilt"]["Defensive"]["23/51-Tionese"]          = new Dictionary<int, string>() { { 1, "613297" }, { 2, "628234" } };
                templates["Hilt"]["Defensive"]["24/56-Columi"]           = new Dictionary<int, string>() { { 1, "640896" }, { 2, "640898" } };
                templates["Hilt"]["Defensive"]["25/58-Rakata"]           = new Dictionary<int, string>() { { 1, "508168" }, { 2, "640899" } };
                // Mod | Resilient:Absorb Elusive:Defense
                templates["Modification"]["Defensive"]["22/50-Green"]    = new Dictionary<int, string>() { { 1, "590964" }, { 2, "590979" } };
                templates["Modification"]["Defensive"]["22/50-Blue"]     = new Dictionary<int, string>() { { 1, "590968" }, { 2, "590987" } };
                templates["Modification"]["Defensive"]["22/50-Purple"]   = new Dictionary<int, string>() { { 1, "623801" }, { 2, "623352" } };
                templates["Modification"]["Defensive"]["23/51-Tionese"]  = new Dictionary<int, string>() { { 1, "628426" }, { 2, "628403" } };
                templates["Modification"]["Defensive"]["24/56-Columi"]   = new Dictionary<int, string>() { { 1, "641768" }, { 2, "641744" } };
                templates["Modification"]["Defensive"]["25/58-Rakata"]   = new Dictionary<int, string>() { { 1, "641769" }, { 2, "641745" } };
                // Enhancement | Sturdiness:Shi/Abs Immunity:Def/Shi
                templates["Enhancement"]["Defensive"]["22/50-Green"]     = new Dictionary<int, string>() { { 1, "626410" }, { 2, "626457" } };
                templates["Enhancement"]["Defensive"]["22/50-Blue"]      = new Dictionary<int, string>() { { 1, "626416" }, { 2, "626463" } };
                templates["Enhancement"]["Defensive"]["22/50-Purple"]    = new Dictionary<int, string>() { { 1, "626400" }, { 2, "626445" } };
                templates["Enhancement"]["Defensive"]["23/51-Tionese"]   = new Dictionary<int, string>() { { 1, "613324" }, { 2, "628692" } };
                templates["Enhancement"]["Defensive"]["24/56-Columi"]    = new Dictionary<int, string>() { { 1, "642550" }, { 2, "642192" } };
                templates["Enhancement"]["Defensive"]["25/58-Rakata"]    = new Dictionary<int, string>() { { 1, "642551" }, { 2, "642193" } };
                // Color Crystal | Vitality, Intrepidity, Indestructible
                templates["ColorCrystal"]["Defensive"]["22/50-Green"]    = new Dictionary<int, string>() { { 1, "299157" }, { 2, "299157" } };
                templates["ColorCrystal"]["Defensive"]["22/50-Blue"]     = new Dictionary<int, string>() { { 1, "299206" }, { 2, "299206" } };
                templates["ColorCrystal"]["Defensive"]["22/50-Purple"]   = new Dictionary<int, string>() { { 1, "299255" }, { 2, "299255" } };
                templates["ColorCrystal"]["Defensive"]["23/51-Tionese"]  = new Dictionary<int, string>() { { 1, "299255" }, { 2, "299255" } };
                templates["ColorCrystal"]["Defensive"]["24/56-Columi"]   = new Dictionary<int, string>() { { 1, "299255" }, { 2, "299255" } };
                templates["ColorCrystal"]["Defensive"]["25/58-Rakata"]   = new Dictionary<int, string>() { { 1, "590782" }, { 2, "590782" } };
                // Augment | Redoubt|Absorb|Shield|Fortitude
                templates["Augment"]["Defensive"]["22/50-Green"]         = new Dictionary<int, string>() { { 1, "503172" }, { 2, "308008" }, { 3, "503151" }, { 4, "503256" } };
                templates["Augment"]["Defensive"]["22/50-Blue"]          = new Dictionary<int, string>() { { 1, "576988" }, { 2, "308036" }, { 3, "576925" }, { 4, "577240" } };
                templates["Augment"]["Defensive"]["22/50-Purple"]        = new Dictionary<int, string>() { { 1, "577016" }, { 2, "308064" }, { 3, "576953" }, { 4, "577268" } };
                templates["Augment"]["Defensive"]["23/51-Tionese"]       = new Dictionary<int, string>() { { 1, "628246" }, { 2, "628267" }, { 3, "628264" }, { 4, "628279" } };
                templates["Augment"]["Defensive"]["24/56-Columi"]        = new Dictionary<int, string>() { { 1, "642574" }, { 2, "642616" }, { 3, "642610" }, { 4, "642640" } };
                templates["Augment"]["Defensive"]["25/58-Rakata"]        = new Dictionary<int, string>() { { 1, "642575" }, { 2, "642617" }, { 3, "642611" }, { 4, "642641" } };
                // Armoring/Hilt | Might, Might Master
              /*templates["Armoring"]["Offensive"]["22/50-Green"]      = new Dictionary<int, string>() { { 1, "483685" }, { 2, "483685" } };
                templates["Armoring"]["Offensive"]["22/50-Blue"]       = new Dictionary<int, string>() { { 1, "483536" }, { 2, "483536" } };
                templates["Armoring"]["Offensive"]["22/50-Purple"]     = new Dictionary<int, string>() { { 1, "483686" }, { 2, "622270" } };
                templates["Armoring"]["Offensive"]["23/51-Tionese"]    = new Dictionary<int, string>() { { 1, "613299" }, { 2, "628240" } };
                templates["Armoring"]["Offensive"]["24/56-Columi"]     = new Dictionary<int, string>() { { 1, "641288" }, { 2, "641290" } };
                templates["Armoring"]["Offensive"]["25/58-Rakata"]     = new Dictionary<int, string>() { { 1, "641289" }, { 2, "341291" } };
                templates["Hilt"]["Offensive"]["22/50-Green"]          = new Dictionary<int, string>() { { 1, "491064" }, { 2, "491064" } };
                templates["Hilt"]["Offensive"]["22/50-Blue"]           = new Dictionary<int, string>() { { 1, "483635" }, { 2, "483635" } };
                templates["Hilt"]["Offensive"]["22/50-Purple"]         = new Dictionary<int, string>() { { 1, "613314" }, { 2, "628506" } };
                templates["Hilt"]["Offensive"]["23/51-Tionese"]        = new Dictionary<int, string>() { { 1, "613299" }, { 2, "628240" } };
                templates["Hilt"]["Offensive"]["24/56-Columi"]         = new Dictionary<int, string>() { { 1, "640888" }, { 2, "640890" } };
                templates["Hilt"]["Offensive"]["25/58-Rakata"]         = new Dictionary<int, string>() { { 1, "508101" }, { 2, "640891" } };
                // Mod | Potent:Crit Deft:Power
                templates["Mod"]["Offensive"]["22/50-Green"]           = new Dictionary<int, string>() { { 1, "623412" }, { 2, "623489" } };
                templates["Mod"]["Offensive"]["22/50-Blue"]            = new Dictionary<int, string>() { { 1, "623422" }, { 2, "623500" } };
                templates["Mod"]["Offensive"]["22/50-Purple"]          = new Dictionary<int, string>() { { 1, "623388" }, { 2, "623465" } };
                templates["Mod"]["Offensive"]["23/51-Tionese"]         = new Dictionary<int, string>() { { 1, "628399" }, { 2, "628407" } };
                templates["Mod"]["Offensive"]["24/56-Columi"]          = new Dictionary<int, string>() { { 1, "641696" }, { 2, "641720" } };
                templates["Mod"]["Offensive"]["25/58-Rakata"]          = new Dictionary<int, string>() { { 1, "641697" }, { 2, "641721" } };
                // Enhancement | Wily:Crit/Sur Proficient:Pow/Acc
                templates["Enhancement"]["Offensive"]["22/50-Green"]   = new Dictionary<int, string>() { { 1, "626410" }, { 2, "626457" } };
                templates["Enhancement"]["Offensive"]["22/50-Blue"]    = new Dictionary<int, string>() { { 1, "626416" }, { 2, "626463" } };
                templates["Enhancement"]["Offensive"]["22/50-Purple"]  = new Dictionary<int, string>() { { 1, "626400" }, { 2, "626445" } };
                templates["Enhancement"]["Offensive"]["23/51-Tionese"] = new Dictionary<int, string>() { { 1, "613324" }, { 2, "628692" } };
                templates["Enhancement"]["Offensive"]["24/56-Columi"]  = new Dictionary<int, string>() { { 1, "642550" }, { 2, "642192" } };
                templates["Enhancement"]["Offensive"]["25/58-Rakata"]  = new Dictionary<int, string>() { { 1, "642551" }, { 2, "642193" } };*/
                // Color crystal
                // Augment

                List<string> ModTypes = new List<string>() { "Armoring", /*"Barrel",*/ "Hilt", "Modification", "Enhancement", "ColorCrystal", "Augment" };
                List<string> Modes = new List<string>() { "Defensive", /*"Offensive"*/ };
                List<string> Levels = new List<string>() { "22/50-Green", "22/50-Blue", "22/50-Purple", "23/51-Tionese", "24/56-Columi", "25/58-Rakata" };

                List<GemmingTemplate> list = new List<GemmingTemplate>();

                foreach (string m in Modes)
                {
                    foreach (string l in Levels)
                    {
                        for (int i = 1; i < 5; i++)
                        {
                            list.Add(new GemmingTemplate()
                            {
                                Model          = "Juggernaut",
                                Group          = l,
                                Enabled        = l == "24/56-Columi" || l == "25/58-Rakata",
                                ArmoringId     = templates["Armoring"]    [m][l][i > 2 ? i - 2 : i],
                                BarrelId       = "0",
                                HiltId         = templates["Hilt"]        [m][l][i > 2 ? i - 2 : i],
                                ModId          = templates["Modification"][m][l][i > 2 ? i - 2 : i],
                                EnhancementId  = templates["Enhancement"] [m][l][i > 2 ? i - 2 : i],
                                ColorCrystalId = templates["ColorCrystal"][m][l][i > 2 ? i - 2 : i],
                                AugmentId      = templates["Augment"]     [m][l][i > 2 ? i - 2 : i],
                            });
                        }
                    }
                }

                /*//              "22/50-Green", "22/50-Blue", "22/50-Purple", "23/51-Tionese", "24/56-Columi", "25/58-Rakata"
                string[][] armr = { new string[] { "483690" }, new string[] { "483518" }, new string[] { "483691", "622240" }, new string[] { "613297", "628234" }, new string[] { "641296", "641298" }, new string[] { "641297", "641299" }, };
                string[][] barl = { new string[] { "0" }, new string[] { "0" }, new string[] { "0", "0" }, new string[] { "0", "0" }, new string[] { "0", "0" }, new string[] { "0", "0" }, };
                string[][] hilt = { new string[] { "483640" }, new string[] { "483509" }, new string[] { "508166", "624296" }, new string[] { "508166", "613312", "628500" }, new string[] { "640896", "640898" }, new string[] { "640897", "508168", "640899" }, };
                string[][] mods = { new string[] { "623741", "623867", "590964" }, new string[] { "623753", "502906", "590968" }, new string[] { "623717", "509852", "623352" }, new string[] { "628426", "628441", "613306" }, new string[] { "641752", "641760", "641768" }, new string[] { "641753", "641761", "641769", "613275" }, };
                string[][] enhm = { new string[] { "591164" }, new string[] { "625246" }, new string[] { "625220", "625231" }, new string[] { "613320", "628605" }, new string[] { "642128", "642130" }, new string[] { "642129", "642131" }, };
                string[][] clcr = {
                    new string[] { "299171", "299164", "299185", "299178", "299157", "299199", "299192" },
                    new string[] { "299220", "299213", "299234", "299227", "299206", "299248", "299241" },
                    new string[] { "0", },
                    new string[] { "0", },
                    new string[] { "0", },
                    new string[] { "299269", "299262", "299283", "299276", "299255", "299297", "299290", "536667", "510809", "512563", "510812", "510808", "536669", "512566", "628750" },
                };
                string[][] augm = {
                    new string[] { "308008", "503151", "503256", "503172" },
                    new string[] { "308036", "576925", "577240", "576988" },
                    new string[] { "308064", "576953", "577268", "577016" },
                    new string[] { "628267", "628264", "628279", "628246" },
                    new string[] { "642616", "642610", "642640", "642574" },
                    new string[] { "642617", "642611", "642641", "642575" },
                };

                for (int tier = 0; tier < 6; tier++)
                {
                    list.AddRange(new GemmingTemplate[] {
                        CreateGemmingTemplate(tier, armr, barl, hilt, mods, enhm, clcr, augm),
                    });
                }*/
                return list;
            }
        }

        private const int DEFAULT_GEMMING_TIER = 5;
        private GemmingTemplate CreateGemmingTemplate(int tier,
            string[][] armoring, string[][] barrel, string[][] hilt,
            string[][] mod, string[][] enhancement, string[][] colorcrystal, string[][] augment)
        {
            return new GemmingTemplate()
            {
                Model = "Juggernaut",
                Group = (new string[] { "22/50-Green", "22/50-Blue", "22/50-Purple", "23/51-Tionese", "24/56-Columi", "25/58-Rakata" })[tier],
                Enabled = (tier == DEFAULT_GEMMING_TIER),

                ArmoringId = armoring[tier][0],
                BarrelId = barrel[tier][0],
                HiltId = hilt[tier][0],
                ModId = mod[tier][0],
                EnhancementId = enhancement[tier][0],
                ColorCrystalId = colorcrystal[tier][0],
                AugmentId = augment[tier][0],

            };
        }

        private ICalculationOptionsPanel _calculationOptionsPanel = null;
        public override ICalculationOptionsPanel CalculationOptionsPanel
        {
            get
            {
                if (_calculationOptionsPanel == null)
                {
                    _calculationOptionsPanel = new CalculationOptionsPanelJuggernaut();
                }
                return _calculationOptionsPanel;
            }
        }

        private string[] _characterDisplayCalculationLabels = null;
        public override string[] CharacterDisplayCalculationLabels
        {
            get
            {
                if (_characterDisplayCalculationLabels == null)
                    _characterDisplayCalculationLabels = new string[] {
                    "Base Stats:Strength",
                    "Base Stats:Presence",
                    "Base Stats:Endurance",
                    "Base Stats:Health",

                    "Defensive Attack Table:Dodge Chance",
                    "Defensive Attack Table:Parry Chance",
                    "Defensive Attack Table:Miss Chance",
                    "Defensive Attack Table:Shield Chance",
                    "Defensive Attack Table:Crit Chance",
                    "Defensive Attack Table:Hit Chance",

                    "Defensive Stats:Armor",
                    "Defensive Stats:Defense Chance",
                    "Defensive Stats:Shield Absorption",
                    "Defensive Stats:Guaranteed Reduction",
                    "Defensive Stats:Avoidance",
                    "Defensive Stats:Total Mitigation",
                    "Defensive Stats:Damage Taken",

                    "Offensive Attack Table:Chance to be Dodged",
                    "Offensive Attack Table:Chance to be Parried",
                    "Offensive Attack Table:Chance to Miss",
                    "Offensive Attack Table:Chance to be Shielded",
                    "Offensive Attack Table:Chance to Crit",
                    "Offensive Attack Table:Chance to Hit",

                    "Defensive Attacks:Threatening Scream*" + ThreateningScream.SDesc.Replace("*", "x"),
                    "Defensive Attacks:Taunt*" + Taunt.SDesc.Replace("*", "x"),
                    "Defensive Attacks:Invincible*" + Invincible.SDesc.Replace("*", "x"),
                    "Defensive Attacks:Endure Pain*" + EndurePain2.SDesc.Replace("*", "x"),
                    "Defensive Attacks:Saber Ward*" + SaberWard.SDesc.Replace("*", "x"),
                    "Defensive Attacks:Unleash*" + Unleash.SDesc.Replace("*", "x"),
                    "Defensive Attacks:Intercede*" + Intercede.SDesc.Replace("*", "x"),
                    "Defensive Attacks:Enrage*" + Enrage.SDesc.Replace("*", "x"),
                    "Defensive Attacks:Chilling Scream*" + ChillingScream.SDesc.Replace("*", "x"),
                    "Defensive Attacks:Intimidating Roar*" + IntimidatingRoar.SDesc.Replace("*", "x"),

                    "Offensive Attacks:Assault*" + Assault.SDesc.Replace("*", "x"),
                    "Offensive Attacks:Sundering Assault*" + SunderingAssault.SDesc.Replace("*", "x"),
                    "Offensive Attacks:Crushing Blow*" + CrushingBlow.SDesc.Replace("*", "x"),
                    "Offensive Attacks:Vicious Slash*" + ViciousSlash.SDesc.Replace("*", "x"),
                    "Offensive Attacks:Retaliation*" + Retaliation.SDesc.Replace("*", "x"),
                    "Offensive Attacks:Ravage*" + Ravage.SDesc.Replace("*", "x"),
                    "Offensive Attacks:Force Scream*" + ForceScream.SDesc.Replace("*", "x"),
                    "Offensive Attacks:Vicious Throw*" + ViciousThrow.SDesc.Replace("*", "x"),
                    "Offensive Attacks:Smash*" + Smash.SDesc.Replace("*", "x"),
                    "Offensive Attacks:Sweeping Slash*" + SweepingSlash.SDesc.Replace("*", "x"),
                    "Offensive Attacks:Backhand*" + Backhand.SDesc.Replace("*", "x"),
                    "Offensive Attacks:Force Choke*" + ForceChoke.SDesc.Replace("*", "x"),
                    "Offensive Attacks:Saber Throw*" + SaberThrow.SDesc.Replace("*", "x"),
                    "Offensive Attacks:Force Charge*" + ForceCharge.SDesc.Replace("*", "x"),
                    "Offensive Attacks:Force Push*" + ForcePush.SDesc.Replace("*", "x"),
                    "Offensive Attacks:Disruption*" + Disruption.SDesc.Replace("*", "x"),
                    "Offensive Attacks:Savage Kick*" + SavageKick.SDesc.Replace("*", "x"),
                    "Offensive Attacks:Pommel Strike*" + PommelStrike.SDesc.Replace("*", "x"),

                    "Offensive Stats:Power",
                    "Offensive Stats:Force Power",
                    "Offensive Stats:Accuracy",
                    "Offensive Stats:Alacrity",
                    "Offensive Stats:Total DPS",
                    "Offensive Stats:Total TPS",
                    "Offensive Stats:Rotation",

                    "Resistances:Kinetic Resist",
                    "Resistances:Energy Resist",
                    "Resistances:Internal Resist",
                    "Resistances:Elemental Resist",

                    "Complex Stats:Ranking Mode*The currently selected ranking mode. Ranking modes can be changed in the Options tab.",
                    @"Complex Stats:Overall Points*Overall Points are a sum of Mitigation and Survival Points. 
Overall is typically, but not always, the best way to rate gear. 
For specific encounters, closer attention to Mitigation and 
Survival Points individually may be important.",
                    @"Complex Stats:Mitigation Points*Mitigation Points represent the amount of damage you mitigate, 
on average, through armor mitigation and avoidance. It is directly 
relational to your Damage Taken. Ideally, you want to maximize 
Mitigation Points, while maintaining 'enough' Survival Points 
(see Survival Points). If you find yourself dying due to healers 
running OOM, or being too busy healing you and letting other 
raid members die, then focus on Mitigation Points.",
                    @"Complex Stats:Survival Points*Survival Points represents the total raw physical damage 
(pre-avoidance/block) you can take before dying. Unlike 
Mitigation Points, you should not attempt to maximize this, 
but rather get 'enough' of it, and then focus on Mitigation. 
'Enough' can vary greatly by fight and by your healers.
If you find that you are being killed by burst damage,
focus on Survival Points.",
                    @"Complex Stats:Threat Points*Threat Points represents the average between unlimited
threat and limited threat scaled by the threat scale.",

                    "Complex Stats:Kinetic Survival",
                    "Complex Stats:Energy Survival",
                    "Complex Stats:Internal Survival",
                    "Complex Stats:Elemental Survival",
                    };
                return _characterDisplayCalculationLabels;
            }
        }

        private string[] _optimizableCalculationLabels = null;
        public override string[] OptimizableCalculationLabels
        {
            get
            {
                if (_optimizableCalculationLabels == null)
                    _optimizableCalculationLabels = new string[] {
                    "Health",
                    "% Total Mitigation",
                    "% Guaranteed Reduction",
                    "% Chance to be Crit",
                    "% Avoidance",
                    "% Avoidance+Shield",
                    "Shield Value",
                    "Threat/sec",
                    "% Chance to be Avoided", 
                    "% Chance to be Dodged",
                    "% Chance to be Parried",
                    "% Chance to Miss",
                    "Burst Time", 
                    "Kinetic Survival",
                    "Energy Survival",
                    "Internal Survival",
                    "Elemental Survival",
                    };
                return _optimizableCalculationLabels;
            }
        }

        private string[] _customChartNames = null;
        public override string[] CustomChartNames
        {
            get
            {
                if (_customChartNames == null)
                    _customChartNames = new string[] {
                    "Ability Damage",
                    "Ability Threat",
                    //"Rotation Damage",
                    //"Rotation Threat",
                    "Combat Table",
                    "Item Budget",
                    };
                return _customChartNames;
            }
        }

        private Dictionary<string, System.Windows.Media.Color> _subPointNameColors = null;
        public override Dictionary<string, System.Windows.Media.Color> SubPointNameColors
        {
            get
            {
                if (_subPointNameColors == null)
                {
                    _subPointNameColors = new Dictionary<string, System.Windows.Media.Color>();
                    _subPointNameColors.Add("Survival", System.Windows.Media.Colors.Blue);
                    _subPointNameColors.Add("Mitigation", System.Windows.Media.Colors.Red);
                    _subPointNameColors.Add("DPS", System.Windows.Media.Colors.Orange);
                    _subPointNameColors.Add("Threat", System.Windows.Media.Colors.Green);
                }
                return _subPointNameColors;
            }
        }

        #region Relevancy

        private List<ItemType> _relevantItemTypes = null;
        public override List<ItemType> RelevantItemTypes
        {
            get
            {
                if (_relevantItemTypes == null)
                {
                    _relevantItemTypes = new List<ItemType>(new ItemType[]
                    {
                        ItemType.None,
                        ItemType.Heavy,
                        ItemType.Ear,
                        ItemType.Implant,
                        ItemType.Relic,
                        ItemType.Lightsaber,
                        ItemType.Vibrosword,
                        ItemType.Shield,
                        ItemType.Focus,
                    });
                }
                return _relevantItemTypes;
            }
        }

        public override bool ItemFitsInSlot(Item item, Character character, CharacterSlot slot, bool ignoreUnique)
        {
            // Only Displays Shields in Off-Hand Slot as Devastate is Shield-Only Post-3.2
            if (slot == CharacterSlot.OffHand && item.Type != ItemType.Shield)
                return false;

            return base.ItemFitsInSlot(item, character, slot, ignoreUnique);
        }

        public override bool IsItemRelevant(Item item)
        {
            // Fishing Poles, they love to muck up the list!
            //if (item.Id == 45991 || item.Id == 25978)
                //return false;
            bool baseRel = base.IsItemRelevant(item);
            bool modMaybeRel = (item.IsModdable && (item.Type == ItemType.Heavy || item.Type == ItemType.Lightsaber));
            bool checkSet = false;
            bool setRelevant = false;
            if (!string.IsNullOrEmpty(item.SetName))
            {
                checkSet = true;
                setRelevant = item.SetName == "Rakata War Leader's Gear"
                           || item.SetName == "Battlemaster War Leader's Gear"
                           || item.SetName == "Rakata Vindicator's Gear"
                           || item.SetName == "Battlemaster Vindicator's Gear";
            }
            if (!checkSet && modMaybeRel)
            {
                if (item.Name.Contains("Exotech")
                    || item.Name.Contains("Xenotech")
                     || item.Name.Contains("Energized")
                     || item.Name.Contains("Ultratech"))
                {
                    if (item.Name.Contains("Combat Medic's")
                        || item.Name.Contains("Combat Tech's")
                        || item.Name.Contains("Eliminator's")
                        || item.Name.Contains("Enforcer's")
                        || item.Name.Contains("Field Medic's")
                        || item.Name.Contains("Field Tech's")
                        || item.Name.Contains("Force-Master's")
                        || item.Name.Contains("Force-Mystic's")
                        || item.Name.Contains("Stalker's")
                        || item.Name.Contains("Supercommando's")
                        || item.Name.Contains("Survivor's")
                        || item.Name.Contains("Weaponmaster's")
                        )
                    {
                        checkSet = true;
                        setRelevant = false;
                    }
                }
            }
            bool retVal = baseRel || (!checkSet && modMaybeRel) || (checkSet && setRelevant && modMaybeRel);
            return retVal;
        }

        public override bool IsBuffRelevant(Buff buff, Character character)
        {
            /*bool NotClassSetBonus = 
                ((buff.Group == "Set Bonuses")
                && (buff.SpellId != 38 && buff.SpellId != 40));// Vindicator's, War Leader's*/
            if (buff.SpellId == 52) { return true; } // S1 Vindicator's PvP
            if (buff.SpellId == 54) { return true; } // S1 War Leader's PvP
            if (buff.SpellId == 38) { return true; } // T1 Vindicator's PvE
            if (buff.SpellId == 40) { return true; } // T1 War Leader's PvE

            if (buff.SpellId == 414790) { return true; } // Unnatural Might would normally be hidden by its BonusHealingMultiplier
            if (buff.SpellId == 221840) { return true; } // Mark of Power would normally be hidden by its Bonus Aim Cunning and Willpower Multipliers

            // Since Absorb Adrenals only give Armor, it's not considered relevant enough to include
            if (buff.SpellId == 612015) { return true; } // Rakata
            if (buff.SpellId == 612001) { return true; } // Exotech
            if (buff.SpellId == 582181) { return true; } // Reusable Hyper-battle
            if (buff.SpellId == 611987) { return true; } // Energized
            if (buff.SpellId == 338399) { return true; } // Hyper-battle

            return base.IsBuffRelevant(buff, character) /*&& !NotClassSetBonus*/;
        }

        public override Stats GetRelevantStats(Stats stats)
        {
            Stats relevantStats = new Stats()
            {
                #region Additive Stats
                #region Super Relevant
                Strength = stats.Strength,
                ShieldRating = stats.ShieldRating,
                DefenseRating = stats.DefenseRating,
                AbsorbRating = stats.AbsorbRating,
                Defense = stats.Defense,
                Shield = stats.Shield,
                Absorb = stats.Absorb,
                Miss = stats.Miss,
                Dodge = stats.Dodge,
                Parry = stats.Parry,
                SpellReflectChance = stats.SpellReflectChance,
                KineticResistance = stats.KineticResistance,
                EnergyResistance = stats.EnergyResistance,
                InternalResistance = stats.InternalResistance,
                ElementalResistance = stats.ElementalResistance,
                #endregion
                #region Relevant
                Endurance = stats.Endurance,
                Health = stats.Health,
                Hp5 = stats.Hp5,
                HealthRestore = stats.HealthRestore,
                HealthRestoreFromMaxHealth = stats.HealthRestoreFromMaxHealth,
                BonusHealingReceived = stats.BonusHealingReceived,
                Power = stats.Power,
                ForcePower = stats.ForcePower,
                AccuracyRating = stats.AccuracyRating,
                CritRating = stats.CritRating,
                SurgeRating = stats.SurgeRating,
                BonusAccuracy = stats.BonusAccuracy,
                BonusBasicAccuracy = stats.BonusBasicAccuracy,
                BonusForceAccuracy = stats.BonusForceAccuracy,
                BonusCritChance = stats.BonusCritChance,
                BonusBasicCritChance = stats.BonusBasicCritChance,
                BonusForceCritChance = stats.BonusForceCritChance,
                BonusTargets = stats.BonusTargets,
                Armor = stats.Armor,
                BonusRageGen = stats.BonusRageGen,
                InterruptProtection = stats.InterruptProtection,
                KineticDamage = stats.KineticDamage,
                EnergyDamage = stats.EnergyDamage,
                InternalDamage = stats.InternalDamage,
                ElementalDamage = stats.ElementalDamage,
                SpellKineticDamageRating = stats.SpellKineticDamageRating,
                SpellEnergyDamageRating = stats.SpellEnergyDamageRating,
                SpellInternalDamageRating = stats.SpellInternalDamageRating,
                SpellElementalDamageRating = stats.SpellElementalDamageRating,
                CritChanceReduction = stats.CritChanceReduction,
                AlacrityRating = stats.AlacrityRating,
                Alacrity = stats.Alacrity,
                ExpertiseRating = stats.ExpertiseRating,
                Expertise = stats.Expertise,
                #endregion
                #endregion
                #region Multiplicative Stats
                #region Super Relevant
                BonusEnduranceMultiplier = stats.BonusEnduranceMultiplier,
                BonusHealthMultiplier = stats.BonusHealthMultiplier,
                HealingReceivedMultiplier = stats.HealingReceivedMultiplier,
                ThreatIncreaseMultiplier = stats.ThreatIncreaseMultiplier,
                BonusArmorMultiplier = stats.BonusArmorMultiplier,
                BonusAbsorbRatingMultiplier = stats.BonusAbsorbRatingMultiplier,
                DefensiveCooldownDurationMultiplier = stats.DefensiveCooldownDurationMultiplier,
                #endregion
                #region Relevant
                BonusStrengthMultiplier = stats.BonusStrengthMultiplier,
                BonusPowerMultiplier = stats.BonusPowerMultiplier,
                BonusSurgeRatingMultiplier = stats.BonusSurgeRatingMultiplier,
                BonusBleedDamageMultiplier = stats.BonusBleedDamageMultiplier,
                BonusDamageMultiplier = stats.BonusDamageMultiplier,
                BonusPeriodicDamageMultiplier = stats.BonusPeriodicDamageMultiplier,
                BonusKineticDamageMultiplier = stats.BonusKineticDamageMultiplier,
                BonusEnergyDamageMultiplier = stats.BonusEnergyDamageMultiplier,
                BonusInternalDamageMultiplier = stats.BonusInternalDamageMultiplier,
                BonusElementalDamageMultiplier = stats.BonusElementalDamageMultiplier,
                FireDamageTakenMultiplier = stats.FireDamageTakenMultiplier,
                #endregion
                #endregion
                #region InverseMultiplicative Stats
                #region Super Relevant
                ThreatReductionMultiplier = stats.ThreatReductionMultiplier,
                ArmorReductionMultiplier = stats.ArmorReductionMultiplier,
                DamageTakenReductionMultiplier = stats.DamageTakenReductionMultiplier,
                SpellDamageTakenReductionMultiplier = stats.SpellDamageTakenReductionMultiplier,
                PhysicalDamageTakenReductionMultiplier = stats.PhysicalDamageTakenReductionMultiplier,
                BossPhysicalDamageDealtReductionMultiplier = stats.BossPhysicalDamageDealtReductionMultiplier,
                BossAttackSpeedReductionMultiplier = stats.BossAttackSpeedReductionMultiplier,
                DefensiveCooldownReductionMultiplier = stats.DefensiveCooldownReductionMultiplier,
                #endregion
                #region Relevant
                ArmorPenetration = stats.ArmorPenetration,
                TargetArmorReduction = stats.TargetArmorReduction,
                #endregion
                #endregion
                #region NonStacking Stats
                #region Super Relevant
                KineticResistanceBuff = stats.KineticResistanceBuff,
                EnergyResistanceBuff = stats.EnergyResistanceBuff,
                InternalResistanceBuff = stats.InternalResistanceBuff,
                ElementalResistanceBuff = stats.ElementalResistanceBuff,
                #endregion
                #region Relevant
                MovementSpeed = stats.MovementSpeed,
                SilenceDurReduc = stats.SilenceDurReduc,
                StunDurReduc = stats.StunDurReduc,
                SnareRootDurReduc = stats.SnareRootDurReduc,
                FearDurReduc = stats.FearDurReduc,
                DisarmDurReduc = stats.DisarmDurReduc,
                #endregion
                #endregion
            };

            foreach (SpecialEffect effect in stats.SpecialEffects())
            {
                if (RelevantTriggers.Contains(effect.Trigger) && HasRelevantStats(effect.Stats))
                {
                    relevantStats.AddSpecialEffect(effect);
                }
            }

            return relevantStats;
        }

        public override bool HasRelevantStats(Stats stats)
        {
            bool superIrrelevant = IsSuperNotRelevant(stats);
            if (superIrrelevant) { return false; }
            bool superRelevant  = IsSuperRelevant(stats);   // Stats that will automatically mark the item as relevant
            bool relevant       = false;                    // Stats which are potentially relevant
            bool notRelevant    = false;                    // Stats which mark the item as irrelevant if not super-relevant

            if (!superRelevant)
            {
                relevant    = IsRelevant(stats);
                notRelevant = IsNotRelevant(stats);

                foreach (SpecialEffect effect in stats.SpecialEffects())
                {
                    if (RelevantTriggers.Contains(effect.Trigger))
                    {
                        superRelevant |= IsSuperRelevant(effect.Stats);
                        if (superRelevant)
                            break;

                        relevant    |= IsRelevant(effect.Stats);
                        notRelevant &= IsNotRelevant(effect.Stats);
                    }
                }
            }

            return (superRelevant || (relevant && !notRelevant));
        }

        private bool IsSuperRelevant(Stats stats)
        {
            #region Additive Stats
            if (stats.Strength != 0) { return true; }
            if (stats.ShieldRating != 0) { return true; }
            if (stats.DefenseRating != 0) { return true; }
            if (stats.AbsorbRating != 0) { return true; }
            if (stats.Defense != 0) { return true; }
            if (stats.Shield != 0) { return true; }
            if (stats.Absorb != 0) { return true; }
            if (stats.Miss != 0) { return true; }
            if (stats.Dodge != 0) { return true; }
            if (stats.Parry != 0) { return true; }
            if (stats.SpellReflectChance != 0) { return true; }
            if (stats.KineticResistance != 0) { return true; }
            if (stats.EnergyResistance != 0) { return true; }
            if (stats.InternalResistance != 0) { return true; }
            if (stats.ElementalResistance != 0) { return true; }
            if (stats.KineticResistanceBuff != 0) { return true; }
            if (stats.EnergyResistanceBuff != 0) { return true; }
            if (stats.InternalResistanceBuff != 0) { return true; }
            if (stats.ElementalResistanceBuff != 0) { return true; }
            #endregion
            #region Multiplicative Stats
            if (stats.BonusEnduranceMultiplier != 0) { return true; }
            if (stats.BonusHealthMultiplier != 0) { return true; }
            if (stats.HealingReceivedMultiplier != 0) { return true; }
            if (stats.ThreatIncreaseMultiplier != 0) { return true; }
            if (stats.BonusArmorMultiplier != 0) { return true; }
            if (stats.BonusAbsorbRatingMultiplier != 0) { return true; }
            if (stats.DefensiveCooldownDurationMultiplier != 0) { return true; }
            #endregion
            #region InverseMultiplicative Stats
            if (stats.ThreatReductionMultiplier != 0) { return true; }
            if (stats.ArmorReductionMultiplier != 0) { return true; }
            if (stats.DamageTakenReductionMultiplier != 0) { return true; }
            if (stats.SpellDamageTakenReductionMultiplier != 0) { return true; }
            if (stats.PhysicalDamageTakenReductionMultiplier != 0) { return true; }
            if (stats.BossPhysicalDamageDealtReductionMultiplier != 0) { return true; }
            if (stats.BossAttackSpeedReductionMultiplier != 0) { return true; }
            if (stats.DefensiveCooldownReductionMultiplier != 0) { return true; }
            #endregion
            #region NonStacking Stats
            if (stats.KineticResistanceBuff != 0) { return true; }
            if (stats.EnergyResistanceBuff != 0) { return true; }
            if (stats.InternalResistanceBuff != 0) { return true; }
            if (stats.ElementalResistanceBuff != 0) { return true; }
            #endregion
            return false;
        }

        private bool IsRelevant(Stats stats)
        {
            #region Additive Stats
            if (stats.Endurance != 0) { return true; }
            if (stats.Health != 0) { return true; }
            if (stats.Hp5 != 0) { return true; }
            if (stats.HealthRestore != 0) { return true; }
            if (stats.HealthRestoreFromMaxHealth != 0) { return true; }
            if (stats.BonusHealingReceived != 0) { return true; }
            if (stats.Power != 0) { return true; }
            if (stats.ForcePower != 0) { return true; }
            if (stats.AccuracyRating != 0) { return true; }
            if (stats.CritRating != 0) { return true; }
            if (stats.SurgeRating != 0) { return true; }
            if (stats.BonusAccuracy != 0) { return true; }
            if (stats.BonusBasicAccuracy != 0) { return true; }
            if (stats.BonusForceAccuracy != 0) { return true; }
            if (stats.BonusCritChance != 0) { return true; }
            if (stats.BonusBasicCritChance != 0) { return true; }
            if (stats.BonusForceCritChance != 0) { return true; }
            if (stats.BonusTargets != 0) { return true; }
            if (stats.BonusCritChance != 0) { return true; }
            //if (stats.Armor != 0) { return true; }
            //if (stats.BonusArmor != 0) { return true; }
            if (stats.BonusRageGen != 0) { return true; }
            if (stats.InterruptProtection != 0) { return true; }
            if (stats.KineticDamage != 0) { return true; }
            if (stats.EnergyDamage != 0) { return true; }
            if (stats.InternalDamage != 0) { return true; }
            if (stats.ElementalDamage != 0) { return true; }
            if (stats.SpellKineticDamageRating != 0) { return true; }
            if (stats.SpellEnergyDamageRating != 0) { return true; }
            if (stats.SpellInternalDamageRating != 0) { return true; }
            if (stats.SpellElementalDamageRating != 0) { return true; }
            if (stats.CritChanceReduction != 0) { return true; }
            if (stats.AlacrityRating != 0) { return true; }
            if (stats.Alacrity != 0) { return true; }
            if (stats.ExpertiseRating != 0) { return true; }
            if (stats.Expertise != 0) { return true; }
            #endregion
            #region Multiplicative Stats
            if (stats.BonusStrengthMultiplier != 0) { return true; }
            if (stats.BonusPowerMultiplier != 0) { return true; }
            if (stats.BonusSurgeRatingMultiplier != 0) { return true; }
            if (stats.BonusBleedDamageMultiplier != 0) { return true; }
            if (stats.BonusDamageMultiplier != 0) { return true; }
            if (stats.BonusPeriodicDamageMultiplier != 0) { return true; }
            if (stats.BonusKineticDamageMultiplier != 0) { return true; }
            if (stats.BonusEnergyDamageMultiplier != 0) { return true; }
            if (stats.BonusInternalDamageMultiplier != 0) { return true; }
            if (stats.BonusElementalDamageMultiplier != 0) { return true; }
            if (stats.FireDamageTakenMultiplier != 0) { return true; }
            #endregion
            #region InverseMultiplicative Stats
            if (stats.ArmorPenetration != 0) { return true; }
            if (stats.TargetArmorReduction != 0) { return true; }
            #endregion
            #region NonStacking Stats
            if (stats.MovementSpeed != 0) { return true; }
            if (stats.SilenceDurReduc != 0) { return true; }
            if (stats.StunDurReduc != 0) { return true; }
            if (stats.SnareRootDurReduc != 0) { return true; }
            if (stats.FearDurReduc != 0) { return true; }
            if (stats.DisarmDurReduc != 0) { return true; }
            #endregion
            return false;
        }

        private bool IsNotRelevant(Stats stats)
        {
            #region Additive Stats
            if (stats.Force != 0) { return true; }
            if (stats.ForceRestore != 0) { return true; }
            if (stats.ForceRestoreFromMaxForcePerSecond != 0) { return true; }
            if (stats.ForceorEquivRestore != 0) { return true; }
            if (stats.Fp5 != 0) { return true; }
            if (stats.SpellCombatForceRegeneration != 0) { return true; }
            if (stats.SpellsForceCostReduction != 0) { return true; }
            if (stats.Healed != 0) { return true; }
            if (stats.HealedPerSP != 0) { return true; }
            if (stats.ScopeDamage != 0) { return true; }
            #endregion
            #region Multiplicative Stats
            if (stats.BonusHealingDoneMultiplier != 0) { return true; }
            if (stats.BonusCritHealMultiplier != 0) { return true; }
            #endregion
            #region InverseMultiplicative Stats
            #endregion
            #region NonStacking Stats
            #endregion
            return false;
        }

        private bool IsSuperNotRelevant(Stats stats)
        {
            if (stats.Aim != 0) { return true; }
            if (stats.Cunning != 0) { return true; }
            if (stats.Willpower != 0) { return true; }
            if (stats.TechPower != 0) { return true; }
            if (stats.BonusCunningMultiplier != 0) { return true; }
            if (stats.BonusAimMultiplier != 0) { return true; }
            if (stats.BonusWillpowerMultiplier != 0) { return true; }
            if (stats.BonusForceMultiplier != 0) { return true; }
            //
            return false;
        }

        #endregion

        public StatsWarrior GetBuffsStats(CollectedCharacter player)
        {
            StatsWarrior statsBuffs = new StatsWarrior();
            statsBuffs.Accumulate(GetBuffsStats(player.Char.ActiveBuffs, player.Char.SetBonusCount));

            if (player.Char.ActiveBuffs.Find<Buff>(x => x.SpellId == (52 ^ 2)) != null) // PvP Vind
            {
                // 2 pieces: Intercede or Guardian Leap heals you for 8% of your total health
                statsBuffs.AddSpecialEffect(_SE_PvP_S1_2P);
            }
            if (player.Char.ActiveBuffs.Find<Buff>(x => x.SpellId == (52 ^ 4)) != null) // PvP Vind
            {
                // 4 pieces: Increases all damage dealt by 10% for 5 seconds after using Force Charge or Force Leap.
                statsBuffs.AddSpecialEffect(_SE_PvP_S1_4P);
            }
            if (player.Char.ActiveBuffs.Find<Buff>(x => x.SpellId == (54 ^ 2)) != null) // PvP War Le
            {
                // 2 pieces: Increases the duration of Force Choke or Force Stasis by 1 second
                statsBuffs.BonusWarrior_ForceChokeDuration = 1f;
            }
            if (player.Char.ActiveBuffs.Find<Buff>(x => x.SpellId == (54 ^ 4)) != null) // PvP War Le
            {
                // 4 pieces: Increases your damage dealt to players by 5% while you Guard another player
                //statsBuffs.BonusDamageMultiplier = 0.05f; // This doesn't apply in PvE
            }
            if (player.Char.ActiveBuffs.Find<Buff>(x => x.SpellId == (38 ^ 2)) != null) // PvE Vind
            {
                // 2 pieces: Lowers the cooldown of Enrage or Combat Focus by 5 seconds
                statsBuffs.BonusWarrior_EnrageCDReduc = 5f;
            }
            if (player.Char.ActiveBuffs.Find<Buff>(x => x.SpellId == (38 ^ 4)) != null) // PvE Vind
            {
                // 4 pieces: Reduces the minimum range of Saber Throw by 10 meters
                statsBuffs.BonusWarrior_SaberThrowMinRangeReduc = 10;
            }
            if (player.Char.ActiveBuffs.Find<Buff>(x => x.SpellId == (40 ^ 2)) != null) // PvE War Le
            {
                // 2 pieces: Increases the duration of Blade Turning by 1 second, and the duration of Invincible or Warding Call by 2 seconds
                statsBuffs.BonusWarrior_BladeTurningDuration = 1f;
                statsBuffs.BonusWarrior_InvincibleDuration = 2f;
            }
            if (player.Char.ActiveBuffs.Find<Buff>(x => x.SpellId == (40 ^ 4)) != null) // PvE War Le
            {
                // 4 pieces: Increases the amount of damage absorbed by Sonic Barrier or Blade Barrier by 20%
                statsBuffs.BonusWarrior_SonicBarrierDamageAbsorbMultiplier = 0.20f;
            }

            return statsBuffs;
        }

        public override void SetDefaults(Character character)
        {
            character.ActiveBuffsAdd("Hunter's Boon");
            character.ActiveBuffsAdd("Unnatural Might");
            character.ActiveBuffsAdd("Mark of Power");
            character.ActiveBuffsAdd("Coordination");

            #region Boss Options
            // Never in back of the Boss
            character.BossOptions.InBack = false;

            int avg = character.AvgWornItemLevel;
            int[] points = new int[] { 126, 136, 140 };
            #region Need a Boss Attack
            character.BossOptions.DamagingTargs = true;
            if (character.BossOptions.DefaultMeleeAttack == null) {
                character.BossOptions.Attacks.Add(BossHandler.ADefaultMeleeAttack);
            }
            if        (avg <= points[0]) {
                character.BossOptions.Health = 1000000;
                character.BossOptions.DefaultMeleeAttack.DamagePerHit = BossHandler.StandardMeleePerHit[(int)BossHandler.TierLevels.T1_8S];
            } else if (avg <= points[1]) {
                character.BossOptions.Health = 1500000;
                character.BossOptions.DefaultMeleeAttack.DamagePerHit = BossHandler.StandardMeleePerHit[(int)BossHandler.TierLevels.T1_16S];
            } else if (avg <= points[2]) {
                character.BossOptions.Health = 2000000;
                character.BossOptions.DefaultMeleeAttack.DamagePerHit = BossHandler.StandardMeleePerHit[(int)BossHandler.TierLevels.T1_8H];
            } else if (avg >  points[2]) {
                character.BossOptions.Health = 2000000;
                character.BossOptions.DefaultMeleeAttack.DamagePerHit = BossHandler.StandardMeleePerHit[(int)BossHandler.TierLevels.T1_16H];
            }
            #endregion
            #endregion
        }

        public override CharacterClass TargetClass { get { return CharacterClass.Juggernaut; } }
        public override ComparisonCalculationBase CreateNewComparisonCalculation() { return new ComparisonCalculationJuggernaut(); }
        public override CharacterCalculationsBase CreateNewCharacterCalculations() { return new CharacterCalculationsJuggernaut(); }

        public override ICalculationOptionBase DeserializeDataObject(string xml)
        {
            System.Xml.Serialization.XmlSerializer serializer =
                new System.Xml.Serialization.XmlSerializer(typeof(CalculationOptionsJuggernaut));
            System.IO.StringReader reader = new System.IO.StringReader(xml);
            CalculationOptionsJuggernaut calcOpts = serializer.Deserialize(reader) as CalculationOptionsJuggernaut;
            return calcOpts;
        }
        #endregion

        #region Talent SpecialEffects
        private List<Trigger> _relevantTriggers = null;
        public List<Trigger> RelevantTriggers {
            get {
                if (_relevantTriggers == null) {
                    _relevantTriggers = new List<Trigger>(){
                        Trigger.Use,
                        Trigger.MeleeCrit,
                        Trigger.MeleeHit,
                        Trigger.MainHandHit,
                        Trigger.CurrentHandHit, // Souldrinker
                        Trigger.PhysicalCrit,
                        Trigger.PhysicalHit,
                        Trigger.DoTTick,
                        Trigger.DamageDone,
                        Trigger.DamageOrHealingDone,
                        Trigger.DamageParried,
                        Trigger.DamageAvoided,
                        Trigger.DamageTaken,
                        Trigger.DamageTakenPutsMeBelow35PercHealth,
                        Trigger.DamageTakenPutsMeBelow50PercHealth,
                        Trigger.ShieldBlock,
                        Trigger.Intercede,
                        Trigger.ForceCharge,
                        Trigger.Retaliation,
                    };
                }
                return _relevantTriggers;
            }
        }

        Type StatsWarriorType = typeof(StatsWarrior);
        // We need these to be static so they aren't re-created

        private static SpecialEffect[] _SE_BladeBarricade = {
            null,
            new SpecialEffect(Trigger.Retaliation, new Stats() { Defense = 0.02f * 1, }, 6f * 1, 6f),
            new SpecialEffect(Trigger.Retaliation, new Stats() { Defense = 0.02f * 2, }, 6f * 2, 6f),
            new SpecialEffect(Trigger.Retaliation, new Stats() { Defense = 0.02f * 3, }, 6f * 3, 6f),
        };
        private static SpecialEffect _SE_PvP_S1_2P = new SpecialEffect(Trigger.Intercede, new Stats() { HealthRestoreFromMaxHealth = 0.08f }, 0, 0);
        private static SpecialEffect _SE_PvP_S1_4P = new SpecialEffect(Trigger.ForceCharge, new Stats() { BonusDamageMultiplier = 0.10f }, 5f, 0);
        private static SpecialEffect _SE_SoresuFormRage = new SpecialEffect(Trigger.DamageTaken, new Stats() { BonusRageGen = 1f }, 0, 6);
        private static SpecialEffect _SE_ShienFormRage = new SpecialEffect(Trigger.Attacked, new Stats() { BonusRageGen = 1f }, 0, 6);
        #endregion

        public override ComparisonCalculationBase[] GetCustomChartData(Character character, string chartName)
        {
            CharacterCalculationsJuggernaut calculations = GetCharacterCalculations(character) as CharacterCalculationsJuggernaut;

            switch (chartName)
            {
                /*
                #region Rotation Damage and Threat
                case "Rotation Damage":
                case "Rotation Threat":
                    {
                        CalculationOptionsJuggernaut options = character.CalculationOptions as CalculationOptionsJuggernaut;
                        string[] rotations = Enum.GetNames(typeof(AttackModelMode));
                        // Optimal rotation will need to be ignored as it is outside the scope of this
                        ComparisonCalculationBase[] comparisons = new ComparisonCalculationBase[rotations.Length - 1];

                        int j = 0;
                        for (int i = 0; i < rotations.Length; i++)
                        {
                            if (rotations[i] != "Optimal")
                            {
                                AttackModel am = new AttackModel(character, calculations.BasicStats, options, (AttackModelMode)Enum.Parse(typeof(AttackModelMode), rotations[i]));
                                ComparisonCalculationJuggernaut comparison = new ComparisonCalculationJuggernaut();
                                comparison.Name = am.Name;

                                if (chartName == "Rotation Damage")
                                    comparison.ThreatPoints = am.DamagePerSecond;
                                else
                                    comparison.ThreatPoints = am.ThreatPerSecond;

                                comparisons[j] = comparison;
                                j++;
                            }
                        }
                        return comparisons;
                    }
                #endregion
                */
                #region Combat Table
                case "Combat Table":
                    {
                        ComparisonCalculationJuggernaut calcMiss = new ComparisonCalculationJuggernaut();
                        ComparisonCalculationJuggernaut calcDodge = new ComparisonCalculationJuggernaut();
                        ComparisonCalculationJuggernaut calcParry = new ComparisonCalculationJuggernaut();
                        ComparisonCalculationJuggernaut calcBlock = new ComparisonCalculationJuggernaut();
                        ComparisonCalculationJuggernaut calcCrit = new ComparisonCalculationJuggernaut();
                        ComparisonCalculationJuggernaut calcHit = new ComparisonCalculationJuggernaut();
                        if (calculations != null)
                        {
                            calcMiss.Name = "Miss";
                            calcDodge.Name = "Dodge";
                            calcParry.Name = "Parry";
                            calcBlock.Name = "Shield";
                            calcCrit.Name = "Crit";
                            calcHit.Name = "Hit";

                            calcMiss.OverallPoints = calcMiss.MitigationPoints = calculations.Miss * 100.0f;
                            calcDodge.OverallPoints = calcDodge.MitigationPoints = calculations.Dodge * 100.0f;
                            calcParry.OverallPoints = calcParry.MitigationPoints = calculations.Parry * 100.0f;
                            calcBlock.OverallPoints = calcBlock.MitigationPoints = calculations.Shield * 100.0f;
                            calcCrit.OverallPoints = calcCrit.SurvivalPoints = calculations.CritVulnerability * 100.0f;
                            calcHit.OverallPoints = calcHit.SurvivalPoints = (1.0f - calculations.AnyAvoid - calculations.CritVulnerability) * 100.0f;
                        }
                        return new ComparisonCalculationBase[] { calcMiss, calcDodge, calcParry, calcBlock, calcCrit, calcHit };
                    }
                #endregion
                #region Item Budget
                case "Item Budget":
                    CharacterCalculationsJuggernaut calcBaseValue = GetCharacterCalculations(character) as CharacterCalculationsJuggernaut;
                    CharacterCalculationsJuggernaut calcStrengthValue = GetCharacterCalculations(character, new Item() { Stats = new Stats() { Strength = 100.0f } }) as CharacterCalculationsJuggernaut;
                    CharacterCalculationsJuggernaut calcAgilityValue = GetCharacterCalculations(character, new Item() { Stats = new Stats() { Cunning = 100.0f } }) as CharacterCalculationsJuggernaut;
                    CharacterCalculationsJuggernaut calcStaminaValue = GetCharacterCalculations(character, new Item() { Stats = new Stats() { Endurance = 150.0f } }) as CharacterCalculationsJuggernaut;
                    CharacterCalculationsJuggernaut calcHealthValue = GetCharacterCalculations(character, new Item() { Stats = new Stats() { Health = 1500.0f } }) as CharacterCalculationsJuggernaut;
                    CharacterCalculationsJuggernaut calcArmorValue = GetCharacterCalculations(character, new Item() { Stats = new Stats() { Armor = 400.0f } }) as CharacterCalculationsJuggernaut;
                    CharacterCalculationsJuggernaut calcDefenseValue = GetCharacterCalculations(character, new Item() { Stats = new Stats() { DefenseRating = 100.0f } }) as CharacterCalculationsJuggernaut;
                    CharacterCalculationsJuggernaut calcHasteValue = GetCharacterCalculations(character, new Item() { Stats = new Stats() { AlacrityRating = 100.0f } }) as CharacterCalculationsJuggernaut;
                    CharacterCalculationsJuggernaut calcExpertiseValue = GetCharacterCalculations(character, new Item() { Stats = new Stats() { ExpertiseRating = 100.0f } }) as CharacterCalculationsJuggernaut;
                    CharacterCalculationsJuggernaut calcHitValue = GetCharacterCalculations(character, new Item() { Stats = new Stats() { AccuracyRating = 100.0f } }) as CharacterCalculationsJuggernaut;

                    return new ComparisonCalculationBase[] { 
                        new ComparisonCalculationJuggernaut() { Name = "100 Strength",
                            OverallPoints = (calcStrengthValue.OverallPoints - calcBaseValue.OverallPoints), 
                            MitigationPoints = (calcStrengthValue.MitigationPoints - calcBaseValue.MitigationPoints),
                            SurvivalPoints = (calcStrengthValue.SurvivalPoints - calcBaseValue.SurvivalPoints),
                            ThreatPoints = (calcStrengthValue.ThreatPoints - calcBaseValue.ThreatPoints)},
                        new ComparisonCalculationJuggernaut() { Name = "100 Agility",
                            OverallPoints = (calcAgilityValue.OverallPoints - calcBaseValue.OverallPoints), 
                            MitigationPoints = (calcAgilityValue.MitigationPoints - calcBaseValue.MitigationPoints),
                            SurvivalPoints = (calcAgilityValue.SurvivalPoints - calcBaseValue.SurvivalPoints),
                            ThreatPoints = (calcAgilityValue.ThreatPoints - calcBaseValue.ThreatPoints)},
                        new ComparisonCalculationJuggernaut() { Name = "150 Stamina",
                            OverallPoints = (calcStaminaValue.OverallPoints - calcBaseValue.OverallPoints), 
                            MitigationPoints = (calcStaminaValue.MitigationPoints - calcBaseValue.MitigationPoints),
                            SurvivalPoints = (calcStaminaValue.SurvivalPoints - calcBaseValue.SurvivalPoints),
                            ThreatPoints = (calcStaminaValue.ThreatPoints - calcBaseValue.ThreatPoints)},
                        new ComparisonCalculationJuggernaut() { Name = "1500 Health",
                            OverallPoints = (calcHealthValue.OverallPoints - calcBaseValue.OverallPoints), 
                            MitigationPoints = (calcHealthValue.MitigationPoints - calcBaseValue.MitigationPoints),
                            SurvivalPoints = (calcHealthValue.SurvivalPoints - calcBaseValue.SurvivalPoints),
                            ThreatPoints = (calcHealthValue.ThreatPoints - calcBaseValue.ThreatPoints)},
                        new ComparisonCalculationJuggernaut() { Name = "400 Armor",
                            OverallPoints = (calcArmorValue.OverallPoints - calcBaseValue.OverallPoints), 
                            MitigationPoints = (calcArmorValue.MitigationPoints - calcBaseValue.MitigationPoints),
                            SurvivalPoints = (calcArmorValue.SurvivalPoints - calcBaseValue.SurvivalPoints),
                            ThreatPoints = (calcArmorValue.ThreatPoints - calcBaseValue.ThreatPoints)},
                        new ComparisonCalculationJuggernaut() { Name = "100 Defense Rating",
                            OverallPoints = (calcDefenseValue.OverallPoints - calcBaseValue.OverallPoints), 
                            MitigationPoints = (calcDefenseValue.MitigationPoints - calcBaseValue.MitigationPoints),
                            SurvivalPoints = (calcDefenseValue.SurvivalPoints - calcBaseValue.SurvivalPoints),
                            ThreatPoints = (calcDefenseValue.ThreatPoints - calcBaseValue.ThreatPoints)},
                        new ComparisonCalculationJuggernaut() { Name = "100 Haste Rating",
                            OverallPoints = (calcHasteValue.OverallPoints - calcBaseValue.OverallPoints), 
                            MitigationPoints = (calcHasteValue.MitigationPoints - calcBaseValue.MitigationPoints),
                            SurvivalPoints = (calcHasteValue.SurvivalPoints - calcBaseValue.SurvivalPoints),
                            ThreatPoints = (calcHasteValue.ThreatPoints - calcBaseValue.ThreatPoints)},
                        new ComparisonCalculationJuggernaut() { Name = "100 Expertise Rating",
                            OverallPoints = (calcExpertiseValue.OverallPoints - calcBaseValue.OverallPoints), 
                            MitigationPoints = (calcExpertiseValue.MitigationPoints - calcBaseValue.MitigationPoints),
                            SurvivalPoints = (calcExpertiseValue.SurvivalPoints - calcBaseValue.SurvivalPoints),
                            ThreatPoints = (calcExpertiseValue.ThreatPoints - calcBaseValue.ThreatPoints)},
                        new ComparisonCalculationJuggernaut() { Name = "100 Hit Rating",
                            OverallPoints = (calcHitValue.OverallPoints - calcBaseValue.OverallPoints), 
                            MitigationPoints = (calcHitValue.MitigationPoints - calcBaseValue.MitigationPoints),
                            SurvivalPoints = (calcHitValue.SurvivalPoints - calcBaseValue.SurvivalPoints),
                            ThreatPoints = (calcHitValue.ThreatPoints - calcBaseValue.ThreatPoints)},
                    };
                #endregion
                default:
                    return new ComparisonCalculationBase[0];
            }
        }

        public override CharacterCalculationsBase GetCharacterCalculations(Character character, Item additionalItem, bool referenceCalculation, bool significantChange, bool needsDisplayCalculations)
        {
            CharacterCalculationsJuggernaut calc = new CharacterCalculationsJuggernaut();
            try {
                #region Setup uniform variables from all models
                // First things first, we need to ensure that we aren't using bad data
                if (character == null) { return calc; }
                CalculationOptionsJuggernaut calcOpts = character.CalculationOptions as CalculationOptionsJuggernaut;
                if (calcOpts == null) { return calc; }
                //
                BossOptions bossOpts = character.BossOptions;
                // Make sure there is at least one attack in the list.
                // If there's not, add a Default Melee Attack for processing
                if (bossOpts.Attacks.Count < 1) {
                    character.IsLoading = true;
                    bossOpts.DamagingTargs = true;
                    bossOpts.Attacks.Add(BossHandler.ADefaultMeleeAttack);
                    character.IsLoading = false;
                }
                // Make sure there is a default melee attack
                // If the above processed, there will be one so this won't have to process
                // If the above didn't process and there isn't one, add one now
                if (bossOpts.DefaultMeleeAttack == null) {
                    character.IsLoading = true;
                    bossOpts.DamagingTargs = true;
                    bossOpts.Attacks.Add(BossHandler.ADefaultMeleeAttack);
                    character.IsLoading = false;
                }
                // Since the above forced there to be an attack it's safe to do this without a null check
                CombatFactors combatFactors;
                GenericRotation Rot;
                StatsWarrior statsRace = null;
                StatsWarrior stats = GetCharacterStats(character, additionalItem, StatType.Average, calcOpts, bossOpts,
                    out statsRace, out combatFactors, out Rot);

                int levelDifference = (bossOpts.Level - character.Level);

                CollectedCharacterJuggernaut collChar = new CollectedCharacterJuggernaut() {
                    Char = character,
                    BossOpts = bossOpts,
                    CalcOpts = calcOpts,
                    //StatS = stats, // Assigned by CombatFactors.Stats
                    Talents = character.JuggernautTalents,
                    CombatFactors = combatFactors,
                    Rotation = Rot,
                    // DefendModel handled below
                };
                #endregion

                collChar.DefendModel = new DefendModel(collChar);
                calc.Duration = bossOpts.BerserkTimer;
                calc.PTRMode = calcOpts.PtrMode;

                calc.AverageStats = collChar.StatS as StatsWarrior;
                if (needsDisplayCalculations) {
                    calc.UnbuffedStats = GetCharacterStats(character, additionalItem, StatType.Unbuffed, calcOpts, bossOpts, out statsRace);
                    calc.BuffedStats = GetCharacterStats(character, additionalItem, StatType.Buffed, calcOpts, bossOpts, out statsRace);
                    calc.BuffsStats = GetBuffsStats(collChar);
                    calc.MaximumStats = GetCharacterStats(character, additionalItem, StatType.Maximum, calcOpts, bossOpts, out statsRace);
                    calc.DefendModel = collChar.DefendModel;
                }

                calc.CombatFactors = combatFactors;
                calc.Rot = Rot;
                calc.BaseHealth = statsRace.Health;
                {// == Attack Table ==
                    // Miss
                    calc.Miss = stats.Miss;
                    calc.AccuracyRating = stats.AccuracyRating;
                    calc.CritRating = stats.CritRating;
                    calc.CritPercent = stats.BonusCritChance;
                    calc.MHCrit = combatFactors.C_PlayersMhChanceToCritTarget_Basic;
                    calc.OHCrit = combatFactors.C_PlayersOhChanceToCritTarget_Basic;
                }
                // Offensive
                calc.AlacrityRating = stats.AlacrityRating;
                calc.AlacrityPercent = stats.Alacrity;

                collChar.CombatFactors.InvalidateCache();
                Rot.Initialize(calc, calc.AverageStats);
                Rot.SetRotationAbilities(collChar.CalcOpts.GetActiveRotationOpener().ClassAbilityPriority,
                    collChar.CalcOpts.GetActiveRotation().ClassAbilityPriority,
                    collChar.CalcOpts.GetActiveRotation().FillerAsType,
                    collChar.CalcOpts.GetActiveRotationExecute().ClassAbilityPriority,
                    collChar.CalcOpts.GetActiveRotationExecute().FillerAsType);
                Rot.Initialize(calc, calc.AverageStats);
                Rot.MakeRotationandDoDPS(needsDisplayCalculations);
                float openerTime = Rot.GetWrapper(typeof(Assault)).OpenerTotalTime / collChar.BossOpts.BerserkTimer;
                float O20Time = Rot.GetWrapper(typeof(Assault)).Ability.TimeOver20Perc - openerTime;
                float U20Time = 1f - O20Time;
                calc.TotalDPS = Rot._DPS_TTL_Opener * openerTime + Rot._DPS_TTL_O20 * O20Time + Rot._DPS_TTL_U20 * U20Time;
                calc.TotalTPS = Rot._TPS_TTL_Opener * openerTime + Rot._TPS_TTL_O20 * O20Time + Rot._TPS_TTL_U20 * U20Time;
                calc.TotalHPS = Rot._HPS_TTL_Opener * openerTime + Rot._HPS_TTL_O20 * O20Time + Rot._HPS_TTL_U20 * U20Time;
                /*if (Rot._DPS_TTL_O20 > 0 && Rot._DPS_TTL_U20 > 0) {
                    calc.TotalDPS = Rot._DPS_TTL_O20 * (1f - (float)bossOpts.Under20Perc) + Rot._DPS_TTL_U20 * ((float)bossOpts.Under20Perc);
                }
                else if (Rot._DPS_TTL_U20 > 0) { calc.TotalDPS = Rot._DPS_TTL_U20; }
                else if (Rot._DPS_TTL_O20 > 0) { calc.TotalDPS = Rot._DPS_TTL_O20; }
                else { calc.TotalDPS = 0f; }
                if (Rot._TPS_TTL_O20 > 0 && Rot._TPS_TTL_U20 > 0) {
                    calc.TotalTPS = Rot._TPS_TTL_O20 * (1f - (float)bossOpts.Under20Perc) + Rot._TPS_TTL_U20 * ((float)bossOpts.Under20Perc);
                }
                else if (Rot._TPS_TTL_U20 > 0) { calc.TotalTPS = Rot._TPS_TTL_U20; }
                else if (Rot._TPS_TTL_O20 > 0) { calc.TotalTPS = Rot._TPS_TTL_O20; }
                else { calc.TotalTPS = 0f; }
                if (Rot._HPS_TTL_O20 > 0 && Rot._HPS_TTL_U20 > 0) {
                    calc.TotalHPS = Rot._HPS_TTL_O20 * (1f - (float)bossOpts.Under20Perc) + Rot._HPS_TTL_U20 * ((float)bossOpts.Under20Perc);
                }
                else if (Rot._HPS_TTL_U20 > 0) { calc.TotalHPS = Rot._HPS_TTL_U20; }
                else if (Rot._HPS_TTL_O20 > 0) { calc.TotalHPS = Rot._HPS_TTL_O20; }
                else { calc.TotalHPS = 0f; }*/

                calc.OtherResourceO20 = Rot.ResourceGenOverDurOtherO20;
                calc.NeedyResourceO20 = Rot.ResourceNeededOverDurO20;
                calc.FreeResourceO20 = calc.OtherResourceO20 - calc.NeedyResourceO20;

                calc.OtherResourceU20 = Rot.ResourceGenOverDurOtherU20;
                calc.NeedyResourceU20 = Rot.ResourceNeededOverDurU20;
                calc.FreeResourceU20 = calc.OtherResourceU20 - calc.NeedyResourceU20;

                #region Special Damage Procs, like Bandit's Insignia or Hand-mounted Pyro Rockets
                calc.SpecProcDPS = calc.SpecProcDmgPerHit = calc.SpecProcActs = 0f;
                if (stats._rawSpecialEffectData != null && character.MainHand != null)
                {
                    bool runIt = false;
                    foreach (SpecialEffect s in stats.SpecialEffects())
                    {
                        if (s.Stats == null) { continue; }
                        if (s.Stats.KineticDamage != 0) { runIt = true; break; }
                        if (s.Stats.EnergyDamage != 0) { runIt = true; break; }
                        if (s.Stats.InternalDamage != 0) { runIt = true; break; }
                        if (s.Stats.ElementalDamage != 0) { runIt = true; break; }
                    }
                    if (runIt)
                    {
                        DamageProcs.SpecialDamageProcs SDP;
                        Dictionary<Trigger, float> triggerIntervals = new Dictionary<Trigger, float>();
                        Dictionary<Trigger, float> triggerChances = new Dictionary<Trigger, float>();
                        CalculateTriggers(collChar, triggerIntervals, triggerChances);
                        SDP = new Rage.DamageProcs.SpecialDamageProcs(character, stats, bossOpts.Level - character.Level,
                            new List<SpecialEffect>(stats.SpecialEffects()),
                            triggerIntervals, triggerChances,
                            bossOpts.BerserkTimer,
                            combatFactors.TargetsDamageReductionMultiplier);

                        calc.SpecProcDPS = SDP.CalculateAll();
                        calc.SpecProcDmgPerHit = SDP.GetDamagePerHit;
                        calc.SpecProcActs = SDP.GetTotalNumProcs;
                    }
                }
                calc.TotalDPS += calc.SpecProcDPS;
                calc.TotalTPS += calc.SpecProcDPS * (1f + collChar.StatS.ThreatIncreaseMultiplier);
                #endregion

                if (needsDisplayCalculations)
                {
                    calc.ArmorReduction = StatConversion.GetArmorDamageReduction(collChar.StatS.Armor, 0f, 0f);

                    calc.DamageTakenPerHit   = collChar.DefendModel.DamagePerHit;
                    calc.DamageTakenPerShield = collChar.DefendModel.DamagePerShield;
                    calc.DamageTakenPerCrit  = collChar.DefendModel.DamagePerCrit;
                    calc.DamageTaken         = collChar.DefendModel.DamagePerSecond;

                    calc.KineticReduction   = (1.0f - CombatFactors.PlayersInternalAndElementalReductionFromAnywhere(collChar, Rage.ItemDamageType.Kinetic));
                    calc.EnergyReduction    = (1.0f - CombatFactors.PlayersInternalAndElementalReductionFromAnywhere(collChar, Rage.ItemDamageType.Energy));
                    calc.InternalReduction  = (1.0f - CombatFactors.PlayersInternalAndElementalReductionFromAnywhere(collChar, Rage.ItemDamageType.Internal));
                    calc.ElementalReduction = (1.0f - CombatFactors.PlayersInternalAndElementalReductionFromAnywhere(collChar, Rage.ItemDamageType.Elemental));
                }

                #region Survivability
                List<Attack> Attacks;
                if (/*calcOpts.SurvScale != 0f &&*/ (Attacks = bossOpts.Attacks.FindAll(a => a.AffectsRole[PLAYER_ROLES.MainTank])).Count > 0) {
                    Dictionary<ItemDamageType, float> countsDmg = new Dictionary<ItemDamageType, float>() {
                        { ItemDamageType.Kinetic, 0f },
                        { ItemDamageType.Energy, 0f },
                        { ItemDamageType.Internal, 0f },
                        { ItemDamageType.Elemental, 0f },
                    };
                    Dictionary<ItemDamageType, float> percDmg = new Dictionary<ItemDamageType, float>() {
                        { ItemDamageType.Kinetic, 0f },
                        { ItemDamageType.Energy, 0f },
                        { ItemDamageType.Internal, 0f },
                        { ItemDamageType.Elemental, 0f },
                    };
                    Dictionary<ItemDamageType, float> highestDmg = new Dictionary<ItemDamageType, float>() {
                        { ItemDamageType.Kinetic, 0f },
                        { ItemDamageType.Energy, 0f },
                        { ItemDamageType.Internal, 0f },
                        { ItemDamageType.Elemental, 0f },
                    };
                    int totalCount = 0;
                    foreach (Attack a in Attacks) {
                        countsDmg[a.DamageType] += 1; totalCount++;
                        if ((a.DamagePerHit + a.DamagePerTick) > highestDmg[a.DamageType]) {
                            highestDmg[a.DamageType] = (a.DamagePerHit + a.DamagePerTick);
                        }
                    }
                    foreach (ItemDamageType t in countsDmg.Keys) { percDmg[t] = countsDmg[t] / (float)totalCount; }
                    float TotalConstantDamageReduction = (stats.Armor > 0 ? 1f - StatConversion.GetArmorDamageReduction(stats.Armor, 0f, 0f) : 1f)
                                                       * (1f - stats.DamageTakenReductionMultiplier)
                                                       * (1f - stats.BossPhysicalDamageDealtReductionMultiplier);
                    Dictionary<ItemDamageType, float> SurvivabilityPointsRaw = new Dictionary<ItemDamageType, float>() {
                        { ItemDamageType.Kinetic,   stats.Health / (1f - TotalConstantDamageReduction) },
                        { ItemDamageType.Energy,    stats.Health / ((1f - StatConversion.GetMinimumResistance(bossOpts.Level, character.Level, stats.EnergyResistance,     0)) * (1f - stats.DamageTakenReductionMultiplier)) },
                        { ItemDamageType.Internal,  stats.Health / ((1f - StatConversion.GetMinimumResistance(bossOpts.Level, character.Level, stats.InternalResistance,   0)) * (1f - stats.DamageTakenReductionMultiplier)) },
                        { ItemDamageType.Elemental, stats.Health / ((1f - StatConversion.GetMinimumResistance(bossOpts.Level, character.Level, stats.ElementalResistance,  0)) * (1f - stats.DamageTakenReductionMultiplier)) },
                    };
                    Dictionary<ItemDamageType, float> SurvivabilityPoints = SoftCapSurvivals(collChar, highestDmg, SurvivabilityPointsRaw);

                    if (stats.HealthRestoreFromMaxHealth > 0) {
                        stats.HealthRestore += stats.HealthRestoreFromMaxHealth * stats.Health * bossOpts.BerserkTimer;
                    }

                    float survs = 0f;
                    foreach (ItemDamageType t in SurvivabilityPoints.Keys) { survs += SurvivabilityPoints[t] * percDmg[t]; }
                    float HealthRest2Surv = survs / 100f + stats.HealthRestore / 100f; // Rotation HPS is already handled
                    calc.TotalHPS += HealthRest2Surv;
                    //calc.Survivability = /*calcOpts.SurvScale **/ HealthRest2Surv;
                } else {
                    // No point in running all those calcs just to zero them out after
                }
                #endregion

                calc.Abilities = collChar.Rotation.TheAbilityList;

                calc.Miss = collChar.DefendModel.DefendTable.Miss;
                calc.Defense = collChar.StatS.Defense;
                calc.Dodge = collChar.DefendModel.DefendTable.Dodge;
                calc.Parry = collChar.DefendModel.DefendTable.Parry;
                calc.Shield = collChar.DefendModel.DefendTable.Shield;
                calc.AnyMiss = collChar.DefendModel.DefendTable.AnyMiss;
                calc.AnyAvoid = collChar.DefendModel.DefendTable.AnyNotLand;
                calc.CritVulnerability = collChar.DefendModel.DefendTable.Crit;
                calc.GuaranteedReduction = collChar.DefendModel.GuaranteedReduction;
                calc.TotalMitigation = collChar.DefendModel.Mitigation;
                calc.DefenseFromTalentsAndBuffs = collChar.Talents.GuardStance * 0.02f;
                calc.ShieldFromTalentsAndBuffs = collChar.Talents.ShieldSpecialization * 0.02f
                    + (collChar.CalcOpts.Stance == (int)JuggStances.SoresuForm ? 0.15f : 0f);
                calc.ShieldFromGenerator = collChar.Char.OffHand != null ? collChar.Char.OffHand.Item.Stats.Shield : 0f;
                calc.AbsorbFromGenerator = collChar.Char.OffHand != null ? collChar.Char.OffHand.Item.Stats.Absorb : 0f;
                calc.Absorb = stats.Absorb;

                calc.KineticSurvivalPoints   = collChar.StatS.Health / (1f - StatConversion.GetArmorDamageReduction(collChar.StatS.Armor, 0f, 0f));
                calc.EnergySurvivalPoints    = collChar.StatS.Health / (1f - StatConversion.GetArmorDamageReduction(collChar.StatS.Armor, 0f, 0f));
                calc.InternalSurvivalPoints  = collChar.StatS.Health / CombatFactors.PlayersInternalAndElementalReductionFromAnywhere(collChar, Rage.ItemDamageType.Internal);
                calc.ElementalSurvivalPoints = collChar.StatS.Health / CombatFactors.PlayersInternalAndElementalReductionFromAnywhere(collChar, Rage.ItemDamageType.Elemental);

                calc.Accuracy = collChar.CombatFactors.AccuracyPercMh_Basic;
                AttackTable table = collChar.Rotation.GetWrapper<Assault>().Ability.MHAtkTable as AttackTable;
                calc.AvoidedAttacks  = table.AnyNotLand;
                calc.DodgedAttacks   = table.Dodge;
                calc.ParriedAttacks  = table.Parry;
                calc.MissedAttacks   = table.Miss;
                calc.ShieldedAttacks = table.Shield;

                calc.BurstTime = collChar.DefendModel.BurstTime;
                calc.RankingMode = collChar.CalcOpts.RankingMode;
                switch (collChar.CalcOpts.RankingMode)
                {
                    case 2:
                        // Burst Time Mode
                        calc.SurvivalPoints      = collChar.DefendModel.BurstTime * 100.0f;
                        calc.MitigationPoints    = 0.0f;
                        calc.ThreatPoints        = 0.0f;
                        break;
                    case 3:
                        // CT Coverage mode
                        calc.SurvivalPoints      = 0.0f;
                        calc.MitigationPoints    = (collChar.DefendModel.DefendTable.Miss + collChar.DefendModel.DefendTable.Parry + collChar.DefendModel.DefendTable.Dodge + collChar.DefendModel.DefendTable.Shield)*10000f;
                        calc.ThreatPoints        = 0.0f;
                        break;
                    default:
                        // Mitigation Scale Mode
                        double survivalCap = collChar.CalcOpts.HitsToSurvive * collChar.BossOpts.DefaultMeleeAttack.DamagePerHit / 1000.0d;
                        double survivalRaw = (collChar.DefendModel.EffectiveHealth + calc.TotalHPS) / 1000.0d;

                        if (survivalRaw <= survivalCap) {
                            calc.SurvivalPoints = collChar.DefendModel.EffectiveHealth + calc.TotalHPS;
                        } else {
                            double topLeft          = Math.Pow(((survivalRaw - survivalCap) / survivalCap) + StatConversion.SurvivalScalerBase, 1.0d / 4.0d);
                            double fraction         = (topLeft - StatConversion.SurvivalScalerTopRight) / 2.0d;
                            double cappedSurvival   = survivalCap * fraction + survivalCap;
                            calc.SurvivalPoints     = (float)cappedSurvival * 1000.0f;
                        }

                        calc.MitigationPoints    = StatConversion.MitigationScaler / (1.0f - collChar.DefendModel.Mitigation);
                        calc.DPSPoints           = calc.TotalDPS * collChar.CalcOpts.DPSScale;
                        calc.ThreatPoints        = calc.TotalTPS * collChar.CalcOpts.ThreatScale;
                        break;
                }
            } catch (Exception ex) {
                new Base.ErrorBox() {
                    Title = "Error in creating Stat Pane Calculations",
                    Function = "GetCharacterCalculations()",
                    TheException = ex,
                }.Show();
            }
            calc.SurvivalPoints = calc.MitigationPoints = 0f;
            return calc;
        }

        static double fourToTheNegativeFourThirds = Math.Pow(4d, -4d / 3d);
        static double topRight = Math.Pow(fourToTheNegativeFourThirds, 1d / 4d);
        public float SoftCapSurv(float raw, float damage) {
            if (damage <= 0f) { return 0f; }
            double survivalCap = damage * 2.0f / 1000d;
            double survivalRaw = raw / 1000d;

            //Implement Survival Soft Cap
            if (survivalRaw <= survivalCap) {
                return 1000f * (float)survivalRaw;
            } else {
                double x = survivalRaw;
                double cap = survivalCap;
                double topLeft = Math.Pow(((x - cap) / cap) + fourToTheNegativeFourThirds, 1d / 4d);
                double fracTop = topLeft - topRight;
                double fraction = fracTop / 2d;
                double y = (cap * fraction + cap);
                return 1000f * (float)y;
            }
        }

        public Dictionary<ItemDamageType, float> SoftCapSurvivals(CollectedCharacterJuggernaut collChar, Dictionary<ItemDamageType, float> highestDmg, Dictionary<ItemDamageType, float> survivalRaws)
        {
            Dictionary<ItemDamageType, float> cappedValues = new Dictionary<ItemDamageType, float>() { };
            //
            foreach (ItemDamageType t in highestDmg.Keys)
            {
                cappedValues[t] = SoftCapSurv(survivalRaws[t], highestDmg[t]);
            }
            //
            return cappedValues;
        }

        public override Stats GetCharacterStats(Character character, Item additionalItem)
        {
            if (character == null) { return new Stats(); }
            try {
                StatsWarrior statsRace = null;
                return GetCharacterStats(character, additionalItem, StatType.Average, (CalculationOptionsJuggernaut)character.CalculationOptions, character.BossOptions, out statsRace);
            } catch (Exception ex) {
                new Base.ErrorBox()
                {
                    Title = "Error in getting Character Stats",
                    Function = "GetCharacterStats()",
                    TheException = ex,
                }.Show();
            }
            return new Stats() { };
        }

        private StatsWarrior GetCharacterStats_Buffed(CollectedCharacterJuggernaut collChar, Item additionalItem, bool isBuffed, out StatsWarrior statsRace)
        {
            if (collChar.CalcOpts == null) { collChar.CalcOpts = collChar.Char.CalculationOptions as CalculationOptionsJuggernaut; }
            if (collChar.BossOpts == null) { collChar.BossOpts = collChar.Char.BossOptions; }
            if (collChar.CombatFactors == null) { collChar.CombatFactors = new CombatFactors(collChar.Char, new StatsWarrior(), collChar.CalcOpts, collChar.BossOpts); }
            JuggernautTalents talents = collChar.Char.JuggernautTalents;

            #region From Race
            statsRace = new StatsWarrior();
            statsRace.Accumulate(BaseStats.GetBaseStats(collChar.Char.Level, CharacterClass.Marauder, collChar.Char.Race));
            #endregion
            #region From Gear/Buffs
            StatsWarrior statsBuffs = (isBuffed ? GetBuffsStats(collChar) : new StatsWarrior());
            StatsWarrior statsItems = new StatsWarrior();
            statsItems.Accumulate(GetItemStats(collChar.Char, additionalItem));
            #endregion
            #region From Options
            StatsWarrior statsOptionsPanel = new StatsWarrior() { };
            switch (collChar.CalcOpts.Form) {
                case JuggStances.ShiiChoForm: {
                    statsOptionsPanel.BonusDamageMultiplier = (1f + statsOptionsPanel.BonusDamageMultiplier) * (1f + 0.03f) - 1f;
                    statsOptionsPanel.DamageTakenReductionMultiplier = 1f - (1f - statsOptionsPanel.DamageTakenReductionMultiplier) * (1f - 0.03f);
                    break;
                }
                case JuggStances.SoresuForm: {
                    statsOptionsPanel.DamageTakenReductionMultiplier = 1f - (1f - statsOptionsPanel.DamageTakenReductionMultiplier) * (1f - 0.06f);
                    statsOptionsPanel.BonusArmorMultiplier = (1f + statsOptionsPanel.BonusArmorMultiplier) * (1f + 0.60f) - 1f;
                    statsOptionsPanel.ThreatIncreaseMultiplier = (1f + statsOptionsPanel.ThreatIncreaseMultiplier) * (1f + 0.50f) - 1f;
                    statsOptionsPanel.Shield += (collChar.Char != null && collChar.Char.OffHand != null && collChar.Char.OffHand.Type == ItemType.Shield ? 0.15f : 0f);
                    statsOptionsPanel.AddSpecialEffect(_SE_SoresuFormRage);
                    break;
                }
                case JuggStances.ShienForm: {
                    statsOptionsPanel.BonusDamageMultiplier = (1f + statsOptionsPanel.BonusDamageMultiplier) * (1f + 0.06f) - 1f;
                    statsOptionsPanel.AddSpecialEffect(_SE_ShienFormRage);
                    break;
                }
                default: { break; }
            }
            #endregion
            #region From Talents
            StatsWarrior statsTalents = new StatsWarrior()
            {
                Defense = 0.02f * talents.GuardStance,
                BonusWarrior_BackhandDamageMultiplier = 0.05f * talents.HeavyHanded,
                BonusWarrior_SmashDamageMultiplier = (1f + 0.05f * talents.HeavyHanded)
                                                   * (1f + 0.10f * talents.Decimate)
                                                   - 1f,
                BonusWarrior_SweepingSlashDamageMultiplier = 0.05f * talents.HeavyHanded,
                BonusWarrior_UnleashCooldownReduc = 15 * talents.Unleashed,
                BonusWarrior_ThreateningScreamCooldownReduc = 7.5f * talents.ThrownGauntlet,
                BonusWarrior_ForcePushCooldownReduc = 7.5f * talents.ThrownGauntlet,
                BonusWarrior_EndurePainDuration = 2.5f * talents.DarkBlood,
                BonusWarrior_SmashCooldownReduc = 1 * talents.Decimate,
                BonusAccuracy = 0.01f * talents.Accuracy,
                BonusStrengthMultiplier = 0.03f * talents.Dreadnaught,
                BonusWarrior_RavageCooldownReduc = 1.5f * talents.Ravager,
                BonusWarrior_ForceChokeCooldownReduc = 5f * talents.Ravager,
                BonusForceCritChance = 0.02f * talents.Malice,
                BonusWarrior_ViciousSlashCritChance = 0.075f * talents.Brutality,
                BonusWarrior_ViciousSlashDamageMultiplier = 0.03f * talents.SaberStrength,
                BonusWarrior_ObliterateDamageMultiplier = 0.03f * talents.SaberStrength,
                Shield = collChar.Char.OffHand != null && collChar.Char.OffHand.Type == ItemType.Shield ? talents.ShieldSpecialization * 0.02f : 0f,
            };
            if (talents.BladeBarricade > 0) { statsTalents.AddSpecialEffect(_SE_BladeBarricade[talents.BladeBarricade]); }
            #endregion

            StatsWarrior statsTotal = new StatsWarrior();
            statsTotal.Accumulate(statsRace);
            statsTotal.Accumulate(statsItems);
            statsTotal.Accumulate(statsBuffs);
            statsTotal.Accumulate(statsTalents);
            statsTotal.Accumulate(statsOptionsPanel);
            statsTotal = UpdateStatsAndAdd(statsTotal, null, collChar.Char);

            statsTotal.Defense += StatConversion.GetDefenseFromRating(statsTotal.DefenseRating);
            statsTotal.Shield += StatConversion.GetShieldFromRating(statsTotal.ShieldRating);
            statsTotal.Absorb += StatConversion.GetAbsorbFromRating(statsTotal.AbsorbRating);

            statsTotal.BonusCritChance += StatConversion.GetCritFromRating(statsTotal.CritRating);
            //statsTotal.BonusCritChance += StatConversion.GetCritFromMainStat(statsTotal.Strength);
            statsTotal.BonusForceCritChance += StatConversion.GetCritFromSecStat(statsTotal.Willpower);

            statsTotal.KineticResistance += statsTotal.KineticResistanceBuff; statsTotal.KineticResistanceBuff = 0;
            statsTotal.EnergyResistance += statsTotal.EnergyResistanceBuff; statsTotal.EnergyResistanceBuff = 0;
            statsTotal.InternalResistance += statsTotal.InternalResistanceBuff; statsTotal.InternalResistanceBuff = 0;
            statsTotal.ElementalResistance += statsTotal.ElementalResistanceBuff; statsTotal.ElementalResistanceBuff = 0;

            return statsTotal;
        }

        private StatsWarrior GetCharacterStats(Character character, Item additionalItem, StatType statType, CalculationOptionsJuggernaut calcOpts, BossOptions bossOpts,
            out StatsWarrior statsRace)
        {
            CombatFactors temp; GenericRotation temp3;
            return GetCharacterStats(character, additionalItem, statType, calcOpts, bossOpts,
                out statsRace, out temp, out temp3);
        }

        private StatsWarrior GetCharacterStats(Character character, Item additionalItem, StatType statType, CalculationOptionsJuggernaut calcOpts, BossOptions bossOpts,
            out StatsWarrior statsRace, out CombatFactors combatFactors, out GenericRotation Rot)
        {
            CollectedCharacterJuggernaut CollChar = new CollectedCharacterJuggernaut { Char = character, CalcOpts = calcOpts, BossOpts = bossOpts, Talents = character.JuggernautTalents, CombatFactors = null, Rotation = null };
            StatsWarrior statsTotal = GetCharacterStats_Buffed(CollChar, additionalItem, statType != StatType.Unbuffed, out statsRace);
            CollChar.StatS = statsTotal;
            combatFactors = new CombatFactors(character, statsTotal, calcOpts, bossOpts); // we have to regenerate it here
            CollChar.CombatFactors = combatFactors;
            CollChar.CombatFactors.InvalidateCache();
            Rot = new GenericRotation(CollChar, 0, 0);
            CollChar.Rotation = Rot;

            if (statType == (StatType.Buffed | StatType.Unbuffed)) { return statsTotal; }
            CollChar.CombatFactors.InvalidateCache();
            Rot.SetRotationAbilities(CollChar.CalcOpts.GetActiveRotationOpener().ClassAbilityPriority, 
                CollChar.CalcOpts.GetActiveRotation().ClassAbilityPriority,
                CollChar.CalcOpts.GetActiveRotation().FillerAsType,
                CollChar.CalcOpts.GetActiveRotationExecute().ClassAbilityPriority,
                CollChar.CalcOpts.GetActiveRotationExecute().FillerAsType);
            // SpecialEffects: Supposed to handle all procs such as Berserking, Mirror of Truth, Grim Toll, etc.
            Rot.Initialize();
            Rot.MakeRotationandDoDPS(false);
            Rot.AddValidatedSpecialEffects(statsTotal, character.JuggernautTalents);

            CollectedCharacterJuggernaut collChar = new CollectedCharacterJuggernaut() {
                CalcOpts = calcOpts,
                BossOpts = bossOpts,
                Char = character,
                CombatFactors = combatFactors,
                Rotation = Rot,
                Talents = character.JuggernautTalents,
                StatS = statsTotal,
            };

            float fightDuration = bossOpts.BerserkTimer;

            if (statType == StatType.Average) {
                DoSpecialEffects(collChar, statsTotal);
            }
            else // if (statType == StatType.Maximum)
            {
                StatsWarrior maxSpecEffects = new StatsWarrior();
                foreach (SpecialEffect effect in statsTotal.SpecialEffects()) maxSpecEffects.Accumulate(effect.Stats);
                return UpdateStatsAndAdd(maxSpecEffects, combatFactors.StatS as StatsWarrior, character);
            }

            // special case for dual wielding w/ berserker enchant on one/both weapons, as they act independently
            //combatFactors.StatS = statsTotal;
            combatFactors.InvalidateCache();
            return combatFactors.StatS as StatsWarrior;
        }

        private void DoSpecialEffects(CollectedCharacterJuggernaut collChar, StatsWarrior statsTotal)
        {
            #region Initialize Triggers
            Dictionary<Trigger, float> triggerIntervals = new Dictionary<Trigger, float>();
            Dictionary<Trigger, float> triggerChances = new Dictionary<Trigger, float>();

            CalculateTriggers(collChar, triggerIntervals, triggerChances);
            #endregion

            List<SpecialEffect> critEffects = new List<SpecialEffect>();

            List<SpecialEffect> firstPass = new List<SpecialEffect>();
            List<SpecialEffect> secondPass = new List<SpecialEffect>();
            List<SpecialEffect> thirdPass = new List<SpecialEffect>();
            foreach (SpecialEffect effect in statsTotal.SpecialEffects())
            {
                effect.Stats.GenerateSparseData();

                if (!triggerIntervals.ContainsKey(effect.Trigger)) continue;
                else if (effect.Stats.CritRating > 0f) { critEffects.Add(effect); }
                else if (effect.Stats.AlacrityRating > 0f ||
                    effect.Stats.AccuracyRating > 0f ||
                    effect.Stats.CritRating > 0f ||
                    effect.Stats.Alacrity > 0f ||
                    effect.Stats.BonusAccuracy > 0f ||
                    effect.Stats.BonusBasicAccuracy > 0f ||
                    effect.Stats.BonusForceAccuracy > 0f ||
                    effect.Stats.BonusCritChance > 0f ||
                    effect.Stats.BonusBasicCritChance > 0f ||
                    effect.Stats.BonusForceCritChance > 0f)
                {
                    // These procs affect rotation
                    firstPass.Add(effect);
                }
                else if (effect.Stats.KineticDamage > 0 ||
                    effect.Stats.EnergyDamage > 0f ||
                    effect.Stats.InternalDamage > 0f ||
                    effect.Stats.ElementalDamage > 0f)
                {
                    // It's a Special Damage Proc
                    thirdPass.Add(effect);
                }
                else
                {
                    // Any other stat proc
                    secondPass.Add(effect);
                }
            }
            StatsWarrior i1 = IterativeSpecialEffectsStats(collChar, firstPass, critEffects, triggerIntervals, triggerChances, true, new StatsWarrior(), collChar.CombatFactors.StatS);
            StatsWarrior i2 = IterativeSpecialEffectsStats(collChar, secondPass, critEffects, triggerIntervals, triggerChances, false, null, collChar.CombatFactors.StatS);
            StatsWarrior i3 = IterativeSpecialEffectsStats(collChar, thirdPass, critEffects, triggerIntervals, triggerChances, false, null, collChar.CombatFactors.StatS);
            StatsWarrior iTtl = new StatsWarrior();
            iTtl.Accumulate(i1);
            iTtl.Accumulate(i2);
            iTtl.Accumulate(i3);
        }

        private static void CalculateTriggers(CollectedCharacterJuggernaut collChar, Dictionary<Trigger, float> triggerIntervals, Dictionary<Trigger, float> triggerChances)
        {
            try
            {
                float fightDuration = collChar.BossOpts.BerserkTimer;
                float fightDurationO20 = collChar.Rotation.FightDurationO20;
                float fightDurationU20 = collChar.Rotation.FightDurationU20;
                float fightDuration2Pass = collChar.CalcOpts.SE_UseDur ? fightDuration : 0;

                float attemptedMH = collChar.Rotation.AttemptedAtksOverDurMH;
                float attemptedOH = collChar.Rotation.AttemptedAtksOverDurOH;
                float attempted = attemptedMH + attemptedOH;

                float landMH = collChar.Rotation.LandedAtksOverDurMH;
                float landOH = collChar.Rotation.LandedAtksOverDurOH;
                float land = landMH + landOH;

                float crit = collChar.Rotation.CriticalAtksOverDur;

                float avoidedAttacks = collChar.CombatFactors.StatS.Dodge + collChar.CombatFactors.StatS.Parry;

                float attemptedAtkInterval = fightDuration / attempted;
                float attemptedAtksIntervalMH = fightDuration / attemptedMH;
                float attemptedAtksIntervalOH = fightDuration / attemptedOH;
                //float landedAtksInterval = fightDuration / land;
                float dmgDoneInterval = fightDuration / land;
                float dmgTakenInterval = 0f;
                {
                    List<Attack> attacks = collChar.BossOpts.Attacks.FindAll(a => a.AffectsRole[PLAYER_ROLES.MeleeDPS] && a.Validate);
                    float frequency = 0;
                    foreach (Attack a in attacks) {
                        frequency += 1f / a.AttackSpeed;
                    }
                    dmgTakenInterval = 1f / frequency;
                }
                
                float hitRate = 1, hitRateMH = 1, hitRateOH = 1, critRate = 1;
                if (attempted != 0f)
                {
                    hitRate = land / attempted;
                    critRate = crit / attempted;
                }
                if (attemptedMH != 0f)
                    hitRateMH = landMH / attemptedMH;
                if (attemptedOH != 0f)
                    hitRateOH = landOH / attemptedOH;

                triggerIntervals[Trigger.Use] = 0f;
                triggerChances[Trigger.Use] = 1f;

                triggerIntervals[Trigger.MeleeAttack] = attemptedAtkInterval;
                triggerChances[Trigger.MeleeAttack] = 1f;

                triggerIntervals[Trigger.MeleeHit] = 
                triggerIntervals[Trigger.PhysicalHit] =
                triggerIntervals[Trigger.CurrentHandHit] = 
                triggerIntervals[Trigger.PhysicalAttack] = attemptedAtkInterval;
                triggerChances[Trigger.MeleeHit] = 
                triggerChances[Trigger.CurrentHandHit] = 
                triggerChances[Trigger.PhysicalHit] = hitRate;
                triggerChances[Trigger.PhysicalAttack] = 1f;

                triggerIntervals[Trigger.PhysicalCrit] = triggerIntervals[Trigger.MeleeCrit] = attemptedAtkInterval;
                triggerChances[Trigger.PhysicalCrit] = triggerChances[Trigger.MeleeCrit] = critRate;

                triggerIntervals[Trigger.MainHandHit] = attemptedAtksIntervalMH;
                triggerChances[Trigger.MainHandHit] = hitRateMH;
                triggerIntervals[Trigger.OffHandHit] = attemptedAtksIntervalOH;
                triggerChances[Trigger.OffHandHit] = hitRateOH;

                triggerIntervals[Trigger.DamageDone] = dmgDoneInterval;
                triggerChances[Trigger.DamageDone] = 1f;

                triggerIntervals[Trigger.DamageOrHealingDone] = dmgDoneInterval; // Need to add Self Heals
                triggerChances[Trigger.DamageOrHealingDone] = 1f;

                triggerIntervals[Trigger.DamageTaken] = dmgTakenInterval;
                triggerChances[Trigger.DamageTaken] = 1f;

                triggerIntervals[Trigger.DamageAvoided] = dmgTakenInterval;
                triggerChances[Trigger.DamageAvoided] = avoidedAttacks;

            } catch (Exception ex) {
                new Base.ErrorBox() {
                    Title = "Error Calculating Triggers",
                    Function = "CalculateTriggers()",
                    TheException = ex,
                }.Show();
            }
        }

        private StatsWarrior IterativeSpecialEffectsStats(CollectedCharacterJuggernaut collChar, List<SpecialEffect> specialEffects, List<SpecialEffect> critEffects,
            Dictionary<Trigger, float> triggerIntervals, Dictionary<Trigger, float> triggerChances,
            bool iterate, StatsWarrior iterateOld, Stats originalStats)
        {
            JuggernautTalents talents = collChar.Char.JuggernautTalents;
            float fightDuration = collChar.BossOpts.BerserkTimer;
            StatsWarrior statsProcs = new StatsWarrior();
            try {
                float dmgTakenInterval = fightDuration / collChar.BossOpts.AoETargsFreq;

                List<Trigger> critTriggers = new List<Trigger>();
                List<float> critWeights = new List<float>();
                bool needsHitTableReset = false;
                foreach (SpecialEffect effect in critEffects) {
                    needsHitTableReset = true;
                    critTriggers.Add(effect.Trigger);
                    critWeights.Add(1f);
                }
                foreach (SpecialEffect effect in specialEffects) {
                    float numProcs = 0;
                    if (effect.Stats.ForceorEquivRestore > 0f && effect.Stats.HealthRestoreFromMaxHealth > 0f) {
                        float value1 = effect.Stats.ForceorEquivRestore;
                        float value2 = effect.Stats.HealthRestoreFromMaxHealth;
                        SpecialEffect dummy = new SpecialEffect(effect.Trigger, new Stats() { ForceorEquivRestore = value1, HealthRestoreFromMaxHealth = value2 }, effect.Duration, effect.Cooldown, effect.Chance) { BypassCache = true };
                        numProcs = dummy.GetAverageProcsPerSecond(dmgTakenInterval, originalStats.Dodge + originalStats.Parry, 0f, 0f) * fightDuration;
                        statsProcs.ForceorEquivRestore += dummy.Stats.ForceorEquivRestore * numProcs;
                        dummy.Stats.ForceorEquivRestore = 0f;
                        ApplySpecialEffect(dummy, collChar, triggerIntervals, triggerChances, ref statsProcs);
                    } else if (effect.Stats.ForceorEquivRestore > 0f) {
                        numProcs = effect.GetAverageProcsPerSecond(dmgTakenInterval, originalStats.Dodge + originalStats.Parry, 0f, 0f) * fightDuration;
                        statsProcs.ForceorEquivRestore += effect.Stats.ForceorEquivRestore * numProcs;
                    } else if (effect.Stats.HealthRestoreFromMaxHealth > 0f) {
                        numProcs = effect.GetAverageProcsPerSecond(dmgTakenInterval, originalStats.Dodge + originalStats.Parry, 0f, 0f) * fightDuration;
                        statsProcs.HealthRestoreFromMaxHealth += effect.Stats.HealthRestoreFromMaxHealth * numProcs;
                    } else {
                        ApplySpecialEffect(effect, collChar, triggerIntervals, triggerChances, ref statsProcs);
                    }
                }

                WeightedStat[] critProcs;
                if (critEffects.Count == 0) {
                    critProcs = new WeightedStat[] { new WeightedStat() { Value = 0f, Chance = 1f } };
                } else if (critEffects.Count == 1) {
                    float interval = triggerIntervals[critEffects[0].Trigger];
                    float chance = triggerChances[critEffects[0].Trigger];
                    float upTime = critEffects[0].GetAverageStackSize(interval, chance, 0,
                        (collChar.CalcOpts.SE_UseDur ? collChar.BossOpts.BerserkTimer : 0f));
                    upTime *= critWeights[0];
                    critProcs = new WeightedStat[] { new WeightedStat() { Value = critEffects[0].Stats.CritRating, Chance = upTime },
                                                     new WeightedStat() { Value = 0f, Chance = 1f - upTime } };
                } else {
                    float[] intervals = new float[critEffects.Count];
                    float[] chances = new float[critEffects.Count];
                    float[] offset = new float[critEffects.Count];
                    for (int i = 0; i < critEffects.Count; i++) {
                        intervals[i] = triggerIntervals[critEffects[i].Trigger];
                        chances[i] = triggerChances[critEffects[i].Trigger];
                    }

                    critProcs = SpecialEffect.GetAverageCombinedUptimeCombinations(critEffects.ToArray(), intervals, chances, offset, critWeights.ToArray(), 0,
                        collChar.BossOpts.BerserkTimer, AdditiveStat.CritRating);
                }
                collChar.CombatFactors.CritProcs = critProcs;
                if (iterate && collChar.Char.MainHand != null && collChar.Char.MainHand.Item != null)
                {
                    foreach (AbilityWrapper aw in collChar.Rotation.DamagingAbilities)
                    {
                        if (aw.Ability.CanCrit && aw.AllNumActivates > 0f)
                        {
                            float tempFactor = (float) Math.Pow(1f - aw.Ability.MHAtkTable.Crit,
                                (aw.AllNumActivates * aw.Ability.SwingsPerActivate * aw.Ability.AvgTargets / fightDuration));
                        }
                    }
                }

                collChar.CombatFactors.StatS = UpdateStatsAndAdd(statsProcs, originalStats as StatsWarrior, collChar.Char);
                collChar.CombatFactors.InvalidateCache();
                //Rot.InvalidateCache();
                if (iterate) {
                    const float precisionWhole = 0.01f;
                    const float precisionDec = 0.0001f;
                    if (statsProcs.AlacrityRating - iterateOld.AlacrityRating > precisionWhole ||
                        statsProcs.AccuracyRating - iterateOld.AccuracyRating > precisionWhole ||
                        statsProcs.CritRating - iterateOld.CritRating > precisionWhole ||
                        statsProcs.Alacrity - iterateOld.Alacrity > precisionDec ||
                        statsProcs.BonusCritChance - iterateOld.BonusCritChance > precisionDec ||
                        statsProcs.BonusAccuracy - iterateOld.BonusAccuracy > precisionDec)
                    {
                        if (needsHitTableReset) collChar.Rotation.ResetHitTables();
                        collChar.Rotation.DoIterations();
                        CalculateTriggers(collChar, triggerIntervals, triggerChances);
                        return IterativeSpecialEffectsStats(collChar,
                            specialEffects, critEffects, triggerIntervals, triggerChances, true, statsProcs, originalStats);
                    } else { /*int j = 0;*/ }
                }

                return statsProcs;
            } catch (Exception ex) {
                new Base.ErrorBox()
                {
                    Title = "Error in creating SpecialEffects Stats",
                    Function = "GetSpecialEffectsStats()",
                    TheException = ex,
                }.Show();
                return new StatsWarrior();
            }
        }

        private float ApplySpecialEffect(SpecialEffect effect, CollectedCharacterJuggernaut collChar, Dictionary<Trigger, float> triggerIntervals, Dictionary<Trigger, float> triggerChances, ref StatsWarrior applyTo)
        {
            float fightDuration = collChar.BossOpts.BerserkTimer;
            float fightDuration2Pass = collChar.CalcOpts.SE_UseDur ? fightDuration : 0;

            Stats effectStats = effect.Stats;

            float upTime = 0f;
            //float avgStack = 1f;
            /*if (effect.Stats.TargetArmorReduction > 0f || effect.Stats.ArmorPenetrationRating > 0f) {
                //int j = 0;
            }*/
            if (effect.Trigger == Trigger.Use) {
                if (effect.Stats._rawSpecialEffectDataSize == 1) {
                    upTime = effect.GetAverageUptime(0f, 1f, 0, fightDuration2Pass);
                    //float uptime =  (effect.Cooldown / fightDuration);
                    List<SpecialEffect> nestedEffect = new List<SpecialEffect>();
                    nestedEffect.Add(effect.Stats._rawSpecialEffectData[0]);
                    StatsWarrior _stats2 = new StatsWarrior();
                    ApplySpecialEffect(effect.Stats._rawSpecialEffectData[0], collChar, triggerIntervals, triggerChances, ref _stats2);
                    effectStats = _stats2;
                } else {
                    upTime = effect.GetAverageStackSize(0f, 1f, 0, fightDuration2Pass); 
                }
            } else if (effect.Duration == 0f && triggerIntervals.ContainsKey(effect.Trigger) && !float.IsInfinity(triggerIntervals[effect.Trigger])) {
                upTime = effect.GetAverageProcsPerSecond(triggerIntervals[effect.Trigger], 
                                                         triggerChances[effect.Trigger],
                                                         0,
                                                         fightDuration2Pass);
            } else if (effect.Trigger == Trigger.ExecuteHit) {
                upTime = effect.GetAverageStackSize(triggerIntervals[effect.Trigger], 
                                                         triggerChances[effect.Trigger],
                                                         0,
                                                         fightDuration2Pass * (float)collChar.BossOpts.Under20Perc);
            } else if (triggerIntervals.ContainsKey(effect.Trigger) && !float.IsInfinity(triggerIntervals[effect.Trigger])) {
                upTime = effect.GetAverageStackSize(triggerIntervals[effect.Trigger], 
                                                         triggerChances[effect.Trigger],
                                                         0,
                                                         fightDuration2Pass);
            }

            if (upTime > 0f) {
                if (effect.Duration == 0f) {
                    applyTo.Accumulate(effectStats, upTime * fightDuration);
                } else if (upTime <= effect.MaxStack) {
                    applyTo.Accumulate(effectStats, upTime);
                }
                return upTime;
            }
            return 0f;
        }

        private static StatsWarrior UpdateStatsAndAdd(StatsWarrior statsToAdd, StatsWarrior baseStats, Character character)
        {
            StatsWarrior retVal;
            float newStaMult = 1f + statsToAdd.BonusEnduranceMultiplier;
            float newStrMult = 1f + statsToAdd.BonusStrengthMultiplier;
            float newBonusArmMult = 1f + statsToAdd.BonusArmorMultiplier;
            float newPowerMult = 1f + statsToAdd.BonusPowerMultiplier;
            float newHealthMult = 1f + statsToAdd.BonusHealthMultiplier;
            float newDefenseRatingMult = 1f + statsToAdd.BonusDefenseRatingMultiplier;
            float newShieldRatingMult = 1f + statsToAdd.BonusShieldRatingMultiplier;
            float newAbsorbRatingMult = 1f + statsToAdd.BonusAbsorbRatingMultiplier;
            if (baseStats != null)
            {
                retVal = baseStats.Clone();

                newStaMult *= 1f + retVal.BonusEnduranceMultiplier;
                newStrMult *= 1f + retVal.BonusStrengthMultiplier;
                newBonusArmMult *= 1f + retVal.BonusArmorMultiplier;
                newPowerMult *= 1f + retVal.BonusPowerMultiplier;
                newHealthMult *= 1f + retVal.BonusHealthMultiplier;
                newDefenseRatingMult *= 1f + statsToAdd.BonusDefenseRatingMultiplier;
                newShieldRatingMult *= 1f + statsToAdd.BonusShieldRatingMultiplier;
                newAbsorbRatingMult *= 1f + statsToAdd.BonusAbsorbRatingMultiplier;

                // normalize retVal with its old base stat values, since we're updating them below
                // This essentially reverses what gets done to statsToAdd, but only things that
                // are affected by multipliers (like base stats, armor, AP, etc)

                retVal.Health -= retVal.Endurance * 10f; // Stamina is affected by a multiplier

                // Since AP is set to (RawAP + 2*STR + A2T + BonusAP)*APMult, and Strength/A2T are affected by mults too,
                // we need to rewind the Strength and Armor components out.  We will add them after we've updated Strength/Armor, below
                retVal.Power /= 1f + retVal.BonusPowerMultiplier;

                // This is reversing the Armor = Armor*BonusMult
                retVal.Armor /= 1f + retVal.BonusArmorMultiplier;

                retVal.DefenseRating /= 1f + retVal.BonusDefenseRatingMultiplier;
                retVal.ShieldRating /= 1f + retVal.BonusShieldRatingMultiplier;
                retVal.AbsorbRating /= 1f + retVal.BonusAbsorbRatingMultiplier;

                retVal.BonusCritChance -= StatConversion.GetCritFromMainStat(retVal.Strength);
            } else { retVal = null; }

            #region Base Stats
            statsToAdd.Endurance  *= newStaMult;
            statsToAdd.Strength *= newStrMult;

            if (retVal != null)
            {
                // change retvals to use the new mults. Combines Stat/=oldMult; Stat*=newMult
                retVal.Endurance *= newStaMult / (1f + retVal.BonusEnduranceMultiplier);
                retVal.Strength *= newStrMult / (1f + retVal.BonusStrengthMultiplier);
            }
            #endregion

            #region Health
            statsToAdd.Health *= newHealthMult;
            statsToAdd.Health += (statsToAdd.Endurance * 10f);
            if (retVal != null)
            {
                // Combines rollback of oldmult and addition of newmult
                retVal.Health *= newHealthMult / (1f + retVal.BonusHealthMultiplier);
                retVal.Health += retVal.Endurance * 10f;
            }
            #endregion

            #region Armor
            statsToAdd.Armor = statsToAdd.Armor * newBonusArmMult;
            if (retVal != null)
            {
                retVal.Armor = retVal.Armor * newBonusArmMult;
            }
            #endregion

            #region Defense/Shield/Absorb Ratings
            statsToAdd.DefenseRating = statsToAdd.DefenseRating * newDefenseRatingMult;
            if (retVal != null) {
                retVal.DefenseRating = retVal.DefenseRating * newDefenseRatingMult;
                retVal.ShieldRating = retVal.ShieldRating * newShieldRatingMult;
                retVal.AbsorbRating = retVal.AbsorbRating * newAbsorbRatingMult;
            }
            #endregion

            #region Attack Power
            // stats to add
            //statsToAdd.Power += (statsToAdd.Strength * 2f);
            statsToAdd.Power *= newPowerMult;
            // reset retval
            if (retVal != null) {
                // already rolled back AP's oldmult, so not combining
                //retVal.Power += (retVal.Strength * 2f);
                retVal.Power *= newPowerMult;
            }
            #endregion

            #region Crit
            statsToAdd.BonusCritChance += StatConversion.GetCritFromMainStat(statsToAdd.Strength);
            if (retVal != null) {
                retVal.BonusCritChance += StatConversion.GetCritFromMainStat(retVal.Strength);
            }
            #endregion

            #region Alacrity
            statsToAdd.Alacrity = (1f + statsToAdd.Alacrity)
                                     - 1f;
            #endregion

            // If we're adding two, then return the .Accumulate
            if (retVal != null) {
                retVal.Accumulate(statsToAdd);
                return retVal;
            } else { return statsToAdd; } // Just processing one, not adding two
        }

#if FALSE
        // This is the old ProtWarr way
        private void AccumulateCharacterStats(CollectedCharacterJuggernaut collChar, Item additionalItem)
        {
            float baseStrength;

            // Base Stats
            collChar.StatS.Endurance = (float)Math.Floor((statsRace.Endurance + statsTalents.Endurance) * (1.0f + collChar.StatS.BonusEnduranceMultiplier));
            collChar.StatS.Endurance += (float)Math.Floor(statsItemsBuffs.Endurance * (1.0f + collChar.StatS.BonusEnduranceMultiplier));
            collChar.StatS.Strength = baseStrength = (float)Math.Floor((statsRace.Strength + statsTalents.Strength) * (1.0f + collChar.StatS.BonusStrengthMultiplier));
            collChar.StatS.Strength += (float)Math.Floor(statsItemsBuffs.Strength * (1.0f + collChar.StatS.BonusStrengthMultiplier));

            // Calculate Procs and Special Effects
            collChar.StatS.Accumulate(GetSpecialEffectStats(collChar));

            // Highest Stat Effects
            // Defensive Stats, Add Difference of First-Pass and Second-Pass Shield/Parry
            collChar.StatS.Armor = (float)Math.Ceiling(collChar.StatS.Armor * (1.0f + collChar.StatS.BaseArmorMultiplier));
            collChar.StatS.ParryRating += ((collChar.StatS.Strength - baseStrength) * 0.27f); // Parry Rating conversion ignores base Strength

            collChar.StatS.KineticResistance += collChar.StatS.KineticResistanceBuff;
            collChar.StatS.EnergyResistance += collChar.StatS.EnergyResistanceBuff;
            collChar.StatS.InternalResistance += collChar.StatS.InternalResistanceBuff;
            collChar.StatS.ElementalResistance += collChar.StatS.ElementalResistanceBuff;

            // Final Derived Stats
            collChar.StatS.Health += StatConversion.GetHealthFromStamina(collChar.StatS.Endurance, CharacterClass.Juggernaut);
            collChar.StatS.Health = (float)Math.Floor(collChar.StatS.Health * (1.0f + collChar.StatS.BonusHealthMultiplier));
            collChar.StatS.Power += collChar.StatS.Strength * 2.0f;
            collChar.StatS.Power = (float)Math.Floor(collChar.StatS.Power * (1.0f + collChar.StatS.BonusPowerMultiplier));
        }

        private StatsWarrior GetSpecialEffectStats(CollectedCharacterJuggernaut player)
        {
            StatsWarrior statsSpecialEffects = new StatsWarrior();

            Dictionary<Trigger, float> triggerIntervals = new Dictionary<Trigger, float>();
            Dictionary<Trigger, float> triggerChances   = new Dictionary<Trigger, float>();

            player.DefendModel = new DefendModel(player);
            player.AttackModel = new AttackModel(player, AttackModelMode.Optimal);

            triggerIntervals[Trigger.Use]                   = 0.0f;
            triggerIntervals[Trigger.MeleeAttack]           = player.AttackModel.WeaponAttacksPerSecond;
            triggerIntervals[Trigger.MainHandHit]           =
            triggerIntervals[Trigger.CurrentHandHit]        =
            triggerIntervals[Trigger.MeleeHit]              = triggerIntervals[Trigger.MeleeAttack];
            triggerIntervals[Trigger.MeleeCrit]             = triggerIntervals[Trigger.MeleeAttack];
            triggerIntervals[Trigger.PhysicalHit]           = triggerIntervals[Trigger.MeleeAttack];
            triggerIntervals[Trigger.PhysicalAttack]        = triggerIntervals[Trigger.MeleeAttack];
            triggerIntervals[Trigger.PhysicalCrit]          = triggerIntervals[Trigger.MeleeAttack];
            triggerIntervals[Trigger.ExecuteHit]            = triggerIntervals[Trigger.MeleeAttack];
            triggerIntervals[Trigger.DoTTick]               = (player.Talents.BattleCry > 0) ? 2.0f : 0.0f;
            triggerIntervals[Trigger.DamageDone]            = triggerIntervals[Trigger.MeleeAttack] + triggerIntervals[Trigger.DoTTick];
            triggerIntervals[Trigger.DamageOrHealingDone]   = triggerIntervals[Trigger.DamageDone];
            triggerIntervals[Trigger.DamageTaken]           = 1.0f / player.DefendModel.AttackerSwingsPerSecond;
            triggerIntervals[Trigger.DamageAvoided]         = triggerIntervals[Trigger.DamageTaken];
            triggerIntervals[Trigger.DamageParried]         = triggerIntervals[Trigger.DamageTaken];
            triggerIntervals[Trigger.DamageTakenPutsMeBelow35PercHealth] = triggerIntervals[Trigger.DamageTaken];
            triggerIntervals[Trigger.ShieldBlock]           = 60f - (player.Talents.BattleCry * 10f);

            triggerChances[Trigger.Use]                     = 1.0f;
            triggerChances[Trigger.MeleeAttack]             = 1.0f;
            triggerChances[Trigger.MainHandHit]             =
            triggerChances[Trigger.CurrentHandHit]          =
            triggerChances[Trigger.MeleeHit]                = player.AttackModel.HitsPerSecond / player.AttackModel.WeaponAttacksPerSecond;
            triggerChances[Trigger.MeleeCrit]               = player.AttackModel.CritsPerSecond / player.AttackModel.WeaponAttacksPerSecond;
            triggerChances[Trigger.PhysicalAttack]          = 1.0f;
            triggerChances[Trigger.PhysicalHit]             = triggerChances[Trigger.MeleeHit];
            triggerChances[Trigger.PhysicalCrit]            = triggerChances[Trigger.MeleeCrit];
            triggerChances[Trigger.ExecuteHit]              = triggerChances[Trigger.MeleeHit];
            triggerChances[Trigger.DoTTick]                 = (player.Talents.BattleCry > 0) ? 1.0f : 0.0f;
            triggerChances[Trigger.DamageDone]              = (player.AttackModel.HitsPerSecond + ((player.Talents.BattleCry > 0) ? 2.0f : 0.0f))
                                                                / (player.AttackModel.WeaponAttacksPerSecond + ((player.Talents.BattleCry > 0) ? 1.0f : 0.0f));
            triggerChances[Trigger.DamageOrHealingDone]     = triggerChances[Trigger.DamageDone];
            triggerChances[Trigger.DamageTaken]             = player.DefendModel.AttackerHitsPerSecond / player.DefendModel.AttackerSwingsPerSecond;
            triggerChances[Trigger.DamageAvoided]           = player.DefendModel.DefendTable.AnyMiss;
            triggerChances[Trigger.DamageParried]           = player.DefendModel.DefendTable.Parry;
            triggerChances[Trigger.DamageTakenPutsMeBelow35PercHealth] = triggerChances[Trigger.DamageTaken] * 0.35f;
            triggerChances[Trigger.ShieldBlock]             = 1.0f;

            foreach (SpecialEffect effect in player.StatS.SpecialEffects())
            {
                if (RelevantTriggers.Contains(effect.Trigger))
                {
                    // Effective Mastery Capping on Large Proc Effects
                    if (effect.Trigger == Trigger.ExecuteHit)
                        effect.AccumulateAverageStats(statsSpecialEffects, triggerIntervals, triggerChances, player.AttackModel.WeaponSpeed, player.BossOpts.BerserkTimer * (float)player.BossOpts.Under20Perc);
                    else
                        effect.AccumulateAverageStats(statsSpecialEffects, triggerIntervals, triggerChances, player.AttackModel.WeaponSpeed, player.BossOpts.BerserkTimer);
                }
            }

            // Base Stats
            statsSpecialEffects.Endurance = (float)Math.Floor(statsSpecialEffects.Endurance * (1.0f + player.StatS.BonusEnduranceMultiplier));
            statsSpecialEffects.Strength = (float)Math.Floor(statsSpecialEffects.Strength * (1.0f + player.StatS.BonusStrengthMultiplier));
            statsSpecialEffects.Cunning = (float)Math.Floor(statsSpecialEffects.Cunning * (1.0f + player.StatS.BonusCunningMultiplier));

            return statsSpecialEffects;
        }

#endif
    }
}
